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

Improve @import directive #749

Closed
noprompt opened this issue May 14, 2013 · 1 comment
Closed

Improve @import directive #749

noprompt opened this issue May 14, 2013 · 1 comment

Comments

@noprompt
Copy link

Originally I posted this here but I think this is a better forum for this appeal.

I've always wanted @import to give you more control over what gets imported and how. While it's very convenient to simply say @import 'blah'; and get everything in blah it has the drawback of making it very difficult to know where certain rules, mixins, etc. are coming from, especially when the stylebase gets heavy. This has given me a few headaches in the past as there can be some unwanted behavior (Ruby's require suffers from the same consequences).

Of course, there are a couple of ways to solve this.

An organized directory structure is one way to help you see where things are coming from (ie.@import "util/clearfix" meaning give me everything in the file util/_clearfix.scss). But there are two tradeoffs that I've encountered. First, you have to be very disciplined. The contents of _clearfix.scss should have no more than whatever is needed to implement clearfix. In this case maybe just a single mixin. Second, provided you are exercising good discipline, you can end up with an explosion of files. It's a hassle and basically amounts to a lot of babysitting.

Another way to avoid some confusion is to prefix mixin and variable names (ie. $foo-line-height or @mixin foo-button). This sort of pattern appears in plenty of other languages with relaxed import mechanisms where stuff is just being dumped in to some global namespace. While it can work, it's really just a cheap hack. To make it a really good hack you'd have to combine it with the solution I mentioned above.

TL;DR you have to be very organized and defensive. I contend this does nothing more than add unnecessary complexity and cognitive load.

So what's the idea? First, let's consider the problem with an example. I have three files style.scss, _foo.scss, and _bar.scss:

// _foo.scss
@mixin quux {
  font-weight: normal;
}

@mixin weeble {
  text-decoration: none;
}

// _bar.scss
@mixin quux {
  font-weight: bold;
}

@mixin weeble {
  text-decoration: underline;
}

// style.scss
@import "foo";
@import "bar";

h1 {
  @include quux;
  @include weeble;
}

From the command line I run sass style.scss and get

h1 {
  font-weight: bold;
  text-decoration: underline; }

That sucks. The contents of _bar.scss are basically overriding the contents of _foo.scss. Surely we can do better. What if we extended @import with just a tiny bit of optional syntax? Consider the following proposals:

// style.scss
@import "foo" (only: quux);
@import "bar" (only: weeble);

h1 {
  @include quux;
  @include weeble;
}

The (only: ident [, ident]*) clause tells Sass to import the only the identifiers listed.

From the command line I run sass style.scss and get

h1 {
  font-weight: normal;
  text-decoration: underline; }

OK. But what if I want to rename, or exclude identifiers?

// style.scss
@import "foo"; 
@import "bar" (exclude: weeble) and (rename: quux bar-quux);

h1 {
  @include quux; // This is foo/quux.
  @include weeble; // This is foo/weeble.
}

h2 {
  @include bar-quux; // This is bar/quux.
}

The (exclude: ident [, ident]*) clause tells Sass to import everything except the identifiers listed. The (rename: l-ident r-ident [, l-ident r-ident]*) clause takes a comma separated list of identifier pairs and tells Sass to import the identifiers listed but rename the first identifier of the pair to the second. We use and to separate clauses.

We run sass style.scss and get

h1 {
  font-weight: normal;
  text-decoration: none; }
h2 {
  font-weight: bold; }

This is extremely nice. I know where code is coming from because it's documented in the import. I have control over the naming when I import which allows me to resolve potential conflicts and avoid unwanted behavior. The additional syntax doesn't break existing code and it looks syntactically similar to other @ prefixed syntax in CSS. Finally, it eliminates most of the defensive programming techniques I mentioned above.

FWIW, I understand that implementing this correctly might be a bit involved and could take some time. There's a lot to think about. But the behavior of @import has been the single biggest pain point for me when using Sass. I know in the past it was proposed to incorporate the Less style namespaces for this sort of thing, but was ultimately rejected for understandable reasons. This however, should it be considered, would be a vastly cleaner approach to handling imports than Less or what's currently available in Sass.

Please take sometime to consider the idea.

@nex3
Copy link
Contributor

nex3 commented May 15, 2013

We're definitely interested in improving the semantics of @import (or rather, creating a new @import-like directives with better semantics). There are a number of use cases we're considering, the ones you bring up here among them. I don't think our ultimate solution will end up looking exactly like this, but hopefully it will address the same problems with the current syntax, and others as well.

In any case, the new import syntax is tracked by #353.

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

2 participants