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

One time imports #139

Closed
chriseppstein opened this issue Jul 15, 2011 · 77 comments
Closed

One time imports #139

chriseppstein opened this issue Jul 15, 2011 · 77 comments
Labels
enhancement New feature or request planned We would like to add this feature at some point

Comments

@chriseppstein
Copy link

We need a way to import library files just a single time. The @import statement is basically like ruby's load directive, but I think we need an import with ruby's require semantics (does nothing if it's been imported already).

What do you think about @depend?

@MarioRicalde
Copy link

This would be for performance, right?

I can think of this being useful on big packages that have one file that does lots of includes.

@chriseppstein
Copy link
Author

Yes. performance is a big part, it allows each module to be used in isolation without a performance penalty. It also makes it easier to override mixins because they won't be re-parsed later if you define the override after the first time it's loaded.

@MarioRicalde
Copy link

I like that last part.. making overriding easier would be great.

@anthonyshort
Copy link

Definitely. This is something I've been seeing a need for lately as well. It would be super handy.

@chriseppstein
Copy link
Author

Marked #156 as a duplicate of this issue.

@seanofw
Copy link

seanofw commented Aug 17, 2011

Copying my proposal from the other thread: I propose adding an @import-once directive that can be dropped into the imported file, as the first statement in that file. It takes no parameters:

@import-once;

This is a safer directive than the @import-vs-@require solution, since it ensures that the imported file can't be accidentally imported wrong; if it was designed to be imported only once, it can assert that itself, and a caller need not know its behavior to be able to use it correctly.

@seanofw
Copy link

seanofw commented Aug 18, 2011

Oh, the other thing in the other thread: If anybody needs it, I have a cute workaround involving adding a @function and an @if statement in the right places; it produces results that are very much like @import-once would produce. It's not perfect, but it does work. You can find my solution here: #156

@chriseppstein
Copy link
Author

@seanofw Can you please provide the use case of a file that is "designed to be imported only once"?

@ZeeAgency
Copy link

+1 for @depend

@seanofw
Copy link

seanofw commented Sep 30, 2011

@chriseppstein: The best example I can give is a diamond-style dependency pattern, which occurs in larger software.

So let's say you have these four files in a big system that's been well-factored into small units:

  • _DropDownMenu.scss
  • _CarModelPicker.scss: @import "DropDownMenu";
  • _ColorPicker.scss: @import "DropDownMenu";
  • FindACarPage.scss: @import "CarModelPicker"; @import "ColorPicker";

So "DropDownMenu" has the stylings for general, shared dropdown menus that appear when somebody clicks a dropdown button. "CarModelPicker" is the layout for a frequently-reused blob of markup that, say, lets a user choose a car by its year and make and model, and that markup contains dropdown menus. "ColorPicker" is the layout for a frequently-reused blob of markup that lets a user choose a color, and that markup also contains dropdown menus. Finally, the "FindACar" page displays both a model-picker and a color-picker to let a user find a car.

See the problem? On the "FindACar" page, if you don't design "DropDownMenu" to be imported only once, you'll get the same dropdown-menu CSS generated twice --- two different places in the same resulting FindACar.css file. You don't need to use @Mixins or anything fancier than @import to demonstrate the problem.

In a large system where the CSS has been heavily sliced-and-diced like this --- like our flagship application with 1.2 million lines of code in it --- the @imports of a single page can end up both broad and deep. It's possible for the same page to unknowingly import, say, "_Links.scss" twenty times, because from the page's perspective, it's listing out its dependencies, and each of those dependencies are listing theirs, and so on until you get to a few base styles that nearly everybody needs.

For a small application, this isn't an issue anyone would notice; but for a big application like ours, avoiding redundant imports is absolutely critical.

@chriseppstein
Copy link
Author

@seanofw I totally understand this pattern and complex structure. My own site is quite complex. but I don't understand why _DropDownMenu.scss should be the one to declare it's importing behavior instead of the caller.

@seanofw
Copy link

seanofw commented Oct 5, 2011

@chriseppstein: The answer is because of the potential for misuse. I work in a large software shop, and believe me, even among really smart, capable coders, if somebody can do it wrong, they will do it wrong.

By making _DropDownMenu.scss the one to declare "You can only import me once," you don't give anybody the option of screwing it up and importing it six times; you can't do it wrong even if you want to. But if _CarModelPicker.scss and _ColorPicker.scss are the ones that are responsible for saying, "Only import DropDownMenu once," that provides two points for failure instead of one: It's two different places where somebody can --- and will --- screw it up. And in a large system, two points for failure quickly become twenty, and those twenty quickly become two hundred.

Putting it inside _DropDownMenu.scss is a form of encapsulation, to use an OO term; _DropDownMenu.scss is then guarding itself against misuse.

Another thing to consider: Is there ever a scenario when it makes sense for a single .scss file to be able to both be imported many times by some callers and only once by others? Is there any scenario where that's sane, desirable behavior? If the answer is no (and I think it's no), then the system should guard against it, because that then must be an accident --- undesirable behavior --- if it happens.

@jacobrask
Copy link

Is depend used in any other language? Using require or import-once would make it familiar to developers from other languages, the latter being the most obvious and very unlikely for anyone to use by mistake.

@verekia
Copy link

verekia commented Apr 3, 2012

This feature seems fundamental for having clean re-usable code in an architecture with inheritance. I wish I had it even for this very simple use case.

Plus, I agree with @jacobrask, and think require and import-once are particularly clear and intuitive.

@MoOx
Copy link

MoOx commented Apr 3, 2012

What about @import "stuff" !once; ?

@ianstormtaylor
Copy link

+1 for require, this would make working with modules much easier
-1 for forcing the callee to declare its import preference

@arbales
Copy link

arbales commented Sep 14, 2012

Being unable to do this in a large modular codebase is a bummer. We ship different combinations of "modules" to our primary web client that we do to secondary clients (widgets, gadgets, etc).

When _buttons.css.sass begins to depend on _gradients.css.sass, but _gradients.css.sass is included on a per-package level (application.sass, gadget.sass,…) to avoid multiple imports, every change in dependencies requires tabulation by the developer or building every package.

I also think allowing the callee to specify this behavior would be interesting, if not expected.

@ianstormtaylor
Copy link

The more I try to develop modular components in SASS the more this feature becomes necessary to not have to deal with the order of dependencies by hand in my main.sass which is easy to screw up and no one wants to maintain comments for.

Letting files require whatever dependencies they need makes things much more obvious than having everything imported once into main.sass. It's the equivalent of storing all of your components as globals in Javascript instead of using something modular like AMD—which makes over-reaching/tight-coupling easy to do by accident, and in general just leads to more tangled code.

So, +1 this a lot.

@zakness
Copy link

zakness commented Oct 24, 2012

Having to include @import-once; in the importee would theoretically reduce the points of possible failure, but it also has the (in my opinion, huge) downside of making the behavior of @import inconsistent. The developer importing files now has to know whether or not the files they're importing expect to be imported once or N times.

I like @depend because it conveys a dependency, which I believe is the main use case for this feature. When I see @require I think of PHP's require function, which does not convey onceness (but that’s probably just because I’m not a Ruby guy :P).

I’m curious, what are some example use cases for importing files multiple times? I’ve worked on large and small projects and this was never something I or my team wanted. Would you consider changing the @import directive itself to always import once?

@JawsomeJason
Copy link

+1000 for this.

@svallory
Copy link

I'm with @zakness, importing a file more than once is the odd scenario. Makes more sense to me going with changing @import to only import once and make @include "filename" include the file no matter what.

@neekey
Copy link

neekey commented Jan 29, 2013

+1 for this feature like @import-once, because when you import a extend-only class multiple times( by mistake... ) , than it will be compiled multiple times... which is exactly not what we want.

@Snugug
Copy link

Snugug commented Jan 29, 2013

@svallory except that @include is already a keyword for mixins in the Scss format and absolutely should not be repurposed for @import-once or some such.

@JawsomeJason
Copy link

+1 to @MoOx's suggestion: @import 'file' !once;

@svallory
Copy link

@Snugug That's kinda the motive behind my suggestion. You see, mixins can be included multiple times. It's already known how @include 'mixing' works. So, by analogy, @include 'file' would work the same way. You may think conflicting files and mixin names would be a problem, but since the context is mutually exclusive, i.e. you always use a @include mixin inside a rule and @include file outside one, it shouldn't be a problem at all.

@Snugug
Copy link

Snugug commented Jan 31, 2013

@svallory That's a dangerous, and in fact incorrect, assumption to make. Mixins absolutely do not need to be included inside a rule, and there are many many "setup" mixins that you in fact specifically do not include inside a rule. Take, for example, Compass' establish-baseline mixin which writes the selectors it needs.

Moreover, I firmly believe that the mental model behind a mixin and a file are different enough that context alone isn't a good enough indicator alone of what you mean to do, especially in the case of files that include mixins of the same name. Take a CSS Normalize file as a for instance. The logical name of the file would probably _normalize.s*ss, and that file contains @mixin normalize and @mixin normalize-legacy. When I call @include normalize, what should I expect to happen? Should I expect the file to be imported again? Should it be the mixin? Both should really only be imported/used once, and both should be written at doc root (outside of a selector).

I personally like @MoOx's !once suggestion as it's a common enough pattern throughout Sass that I think it's a good fit (we've got !default for variables and !optional for extends).

@arbales
Copy link

arbales commented Jan 31, 2013

The @include debate isn't relevant for me since I use (and will forever
use) indented Sass, but for the sake of simplicity, clarity, and
universality, @require seems like the right call to me.

I'm more interested in seeing this happen than I am attached to any
specific implementation or semantics though!

On Thursday, January 31, 2013, Snugug wrote:

@svallory https://github.com/svallory That's a dangerous, and in fact
incorrect, assumption to make. Mixins absolutely do not need to be included
inside a rule, and there are many many "setup" mixins that you in fact
specifically do not include inside a rule. Take, for example, Compass'
establish-baseline mixinhttp://compass-style.org/reference/compass/typography/vertical_rhythm/#mixin-establish-baselinewhich writes the selectors it needs.

Moreover, I firmly believe that the mental model behind a mixin and a file
are different enough that context alone isn't a good enough indicator alone
of what you mean to do, especially in the case of files that include mixins
of the same name. Take a CSS Normalize file as a for instance. The logical
name of the file would probably _normalize.s*ss, and that file contains @mixin
normalize and @mixin normalize-legacy. When I call @include normalize,
what should I expect to happen? Should I expect the file to be imported
again? Should it be the mixin? Both should really only be imported/used
once, and both should be written at doc root (outside of a selector).

I personally like @MoOx https://github.com/MoOx's !once suggestion as
it's a common enough pattern throughout Sass that I think it's a good fit
(we've got !default for variables and !optional for extends).


Reply to this email directly or view it on GitHubhttps://github.com//issues/139#issuecomment-12947011.

@svallory
Copy link

@Snugug thank you for your comment. I missed that point. I have nothing more to say than I totally agree with you.

@JawsomeJason
Copy link

Eh, I generally keep most of my placeholders on a mobile-first context, meaning they apply to all. I try not to complicate that part too much.

@JawsomeJason
Copy link

Give it 10 years and we'll see native placeholders for CSS... guaranteed.

@xzyfer
Copy link

xzyfer commented Sep 6, 2013

Can you please elaborate further?
AFAIK you cannot extend a placeholder inside a media query unless it was defined within that media query. Although sass currently allows this, and does the right thing, it throws deprecation warnings stating it'll no longer function in 3.3

@brauliobo
Copy link

hello all, this issue is quite old. I've just reported a duplicated of this #928 .
Is there a fix for this in the near future??

@JawsomeJason
Copy link

xzyfer: I just mean that I try not to create placeholders that would need to be overwritten in MQs.

brauliobo: read through for an import-once function.

@brauliobo
Copy link

@TheJase: @import-once is integrated into the official code?

@brauliobo
Copy link

pasting https://gist.github.com/courtsimas/1167053 before including anything isn't nice. this or another solution should be on the sass core code

@JawsomeJason
Copy link

Why is it not nice?  It is actually safer and more specific (you specify you should only include this once in the actual file). 

And no. No official support yet. But I actually feel this is safer than a native @import-once. 


Sent from Mailbox for iPhone

On Sat, Sep 28, 2013 at 9:10 AM, Bráulio Bhavamitra
notifications@github.com wrote:

pasting https://gist.github.com/courtsimas/1167053 before including anything isn't nice. this or another solution should be on the sass core code

Reply to this email directly or view it on GitHub:
#139 (comment)

@brauliobo
Copy link

it is not nice because it adds more than 10 lines of code in each sass file I need it.

@aaronjensen
Copy link

How would it be "safer"? The gist is clever, but it's a total hack in my opinion. For one, it requires you to wrap each file you want to be able to protect in an if, so you couldn't use it w/ any files you don't own, for another it requires you to litter your top level files w/ that function code. I'm holding out for a native version.

@brauliobo
Copy link

@aaronjensen +1 for a native version. it is very needed. the sass developers are considering this??

@JawsomeJason
Copy link

Safer because your other devs don't need to remember to use an @import-once over and over (humans are flawed like that). 

And if you don't own the code, just wrap the check around the import instead. 

More specific, less magic. 


Sent from Mailbox for iPhone

On Sat, Sep 28, 2013 at 9:24 AM, Bráulio Bhavamitra
notifications@github.com wrote:

@aaronjensen +1 for a native version. it is very needed. the sass developers are considering this??

Reply to this email directly or view it on GitHub:
#139 (comment)

@svallory
Copy link

@brauliobo it's not a built in solution, but you can use SmartSass. It will use the SSS compiler you have installed but replace the importer by one which makes include import files only once

@brauliobo
Copy link

@svallory why shouldn't it be built in?

@JawsomeJason
Copy link

@brauliobo He's not saying it shouldn't. He's saying this is a possible solution in the meantime.

@svallory
Copy link

@brauliobo It's not "built in" because it's not part of the sass compiler. But it's totally transparent for the apps using it. And I sure hope it will be made part of sass someday.

@StefanoRausch
Copy link

@brauliobo : I do have a slight variation of the solution mentioned above — see https://gist.github.com/StefanoRausch/6744610 .

I do import it only once at the very beginning —think framework here, no duplication in every Sass file — and from there on I only have to either wrap the code in discussion as content for the mixin or I can use the function, depending on the constraints set by the mixin.

@import file -> @include once( "" ) { ... } OR @if( include-once( "" ) { ... }

Still a workaround, but nice to have ;)

@StefanoRausch
Copy link

See #156 too.

@chriseppstein
Copy link
Author

@Frikki
Copy link

Frikki commented Oct 13, 2014

Three years... and counting!

@herringtown
Copy link

Tick, tock.....thought this would have been addressed by now, having read through the entire thread.

Are @StefanoRausch & @courtsimas workarounds still the only viable solution to not have duplicated css when extending a selector from another (imported) file?

@tmccombs
Copy link

tmccombs commented Jan 5, 2015

Why is this still not fixed? Almost every language has some sort of import-once mechanism, but not sass.

@chriseppstein
Copy link
Author

Because it's a 4.0 feature.

@sass sass locked and limited conversation to collaborators Jan 5, 2015
@nex3 nex3 removed this from the 4.0 milestone Jul 13, 2018
@nex3
Copy link
Contributor

nex3 commented Dec 26, 2018

Closing this in favor of #1094.

@nex3 nex3 closed this as completed Dec 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request planned We would like to add this feature at some point
Projects
None yet
Development

No branches or pull requests