-
Notifications
You must be signed in to change notification settings - Fork 465
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
Implement support for multiple importers #1000
Conversation
ce2abd4
to
4b8c486
Compare
Possibly related. Is it possible to get a list of files used by the file compiler? This would be super handy for implementor building a file watcher. That rebuilds correctly based off imported file changes. |
@drewwells you are probably looking for |
5f7c939
to
6aeec11
Compare
6aeec11
to
8942168
Compare
8b506e5
to
e159403
Compare
d302b0f
to
293eb55
Compare
This looks quite interesting @mgreter. 👍 I will try to wrap my head around how to provision the priority thing in JS and/or decent way to capture the intent of user that which kind of import they want to handle with certain importer, so to translate that in API call. Currently, I am under the impression that we will allow user to make their decision and return null; whether certain importer wants to handle certain kind of URI? In which case, the user will return Please CMIIW. +1 to add it in v3.2. We already have fistful of breaking changes coming in node-sass v3, why not another! 😎 |
@am11 yup, spot on. Also check out custom headers, which are registered exactly the same way as importers. Only difference is that all custom headers will be called and their imports get accumulated. It's really just an array of importers that get called at the start of each compilation. As for the priority, you may be able to attach a priority property to the js function? Like so: function importer(...) {
return ['filename', 'div { ... }'];
}
importer.priority = 99;
var options = {
// old and obsolete
// importer => importer,
importers => [
importer, // = importer.priority || 0
[ importer, 5 ] // = 5 || importer.priority
]
} In perl I opted for a simple array ref: headers => [
header1, // will get default = 0
[ header2, 1] // gets specific prio
] What priorities people give to their importers is pretty much out of this scope, but I could propose these very personal guidelines, which are probably really just a bad first guess:
|
This is brilliant! ⚡ I think we can let node-oriented users return the priority as member of object, instead of doing something fancy/tricky like As for the custom headers, I will try to add it to v3, but I am not sure if we would have enough time after this gets merged and libsass v3.2.0 stable is released? Will there be another beta or rc, so we have time to include these features and be able to align node-sass v3.0 release with libsass 3.2? |
Be aware that the priority has to be passed to libsass before the importer gets called (you cannot include it in the return of the importer). And yes, I could merge this PR and create another beta, so node-sass can catch up and do another beta on its own, so things can get settled! IMO you should be able to copy pretty much all code from custom importers for custom headers. |
I just envisioned it how it will look, and let me tell you this much: this is going to be fun 😎 ☀️ We will need to provide the following variants:
Same goes for the headers. Aside: we really need help from someone to document all that libsass via node-sass has to offer to node.js paradigm. |
After all, this is issue #:100:0 ! |
Implement support for multiple importers
I'm getting cannot find errors on
|
It looks like it was renamed to |
That is helpful! The code indexes the C array directly rather than use a |
I am opposed to the custom headers feature. One of the philosophies that Sass has is that we do not support things "magically being available". Only explicit declarations can and should bring in code dependencies. This is why there's no way to set a global variable from the sass command line despite numerous requests. Custom importers are a great way to bring in code that is constructed on the fly. That is how compass sprites worked. They imported the sprite images. IMO, we don't need a new abstraction here, the custom importer concept is enough. |
Load paths is just a simple way to make a filesystem importer. In this way, importers are actually the first class citizens and it allows importers and filesystem paths to be intermixed. Furthermore, the resolution order should just be a list IMO. I don't understand why we need priority. |
Custom functions is the new way of supporting the import overrides in Ruby Since libsass has no custom mixin support, headers fill that gap quite On Wed, Apr 1, 2015 at 5:17 PM Chris Eppstein [email protected]
|
We have two ways to add custom functions, headers and importers in libsass. Via the C-API options for implementers or by loading native libsass plugins. So the priority is needed since we have more than one array to consider. From the libsass implementation it's just a slightly different use of custom importers, so the feature was quite cheap and I do see the benefits in regard to native plugins. |
I get that custom functions violate the "magically available" principle that I mentioned. As such, I've been proposing that we move away from that pattern (sass/sass#1608 (comment)) so that even functions have to be loaded explicitly to be available in a sass file's compile. I get that you find it useful, but it's moving libsass in a direction that sass itself is moving away from. I don't understand why you think libsass needs "custom mixins". Mixins come from imports. If you want to provide a mixin, you either provide a sass file or you provide a custom importer. The reason we need custom functions is to do things that pure sass cannot do, like filesystem access, or integration with build systems, etc. These functions can return whatever information the mixins need. |
@mgreter OK, I get that native plugins have this issue, but the priority value is really unintuitive to me. There's no agreement what any priority value means and any scheme that may arise would likely be better implemented in a less granular way. IMO, the priority from native plugins should be limited to |
Loading specific functions would be rather tedious. Maybe packages that Thinking of this problem like most modern language. IDEs provide support On Wed, Apr 1, 2015 at 6:18 PM Chris Eppstein [email protected]
|
@chriseppstein I agree that it is probably over engineered to expose the priority to the "options" C-API (which is what implementers use). From our point it is just convenient to have exactly the same transfer C objects for both C-APIs. IMO it doesn't make much sense to create new functions in the C-API just to maneuver around this. Instead we should indeed give some guidance which ranges are for what use. I already posted something in that direction:
We also could enfore certain ranges for plugins. But I don't know what you mean by "before the load path". IMO the use case where you simply have a list of importers/headers is possible, as libsass should execute same priorities in registration order (but I have to confess, I didn't really test this). @chriseppstein is this a showstopper for you for the upcoming 3.2.0 release? The API is still marked highly experimental, so IMO it should be ok for now. IMO we can further discuss this to get to an agreement on a |
Apologies if I've missed something, I'm just catching up on all the recent changes. I think we may have prematurely over-engineered the extensibility points. I think it's worth stepping back and questioning do we really need custom functions, importers, and headers? And what are the real world usecases they solve? I'm struggling to see what the usecase for custom headers is? As @chriseppstein has mentioned custom mixins don't really make sense. |
For the time being it's my opinion we should disable custom headers in 3.2.0. Let's open an RFC to discuss the intention, usecases, and implementation of this feature. The C API is quickly becoming a major feature of Libsass and it's worth doing the due diligence on changes and features - this is especially important in cases where there is no Ruby Sass / Compass equivalent. It's probably worth also opening an RFC regarding importer weights. I agree that it should be a list, rather than weighted. The pragmatist in me sees this quickly becoming a race to the top ala z-indexes. |
Since this has been merged lets continue the custom import discussion to #1034 |
This PR now implements all options I envisioned in #962. At this point I'm not sure if we want to include this in 3.2.0 or wait for 3.2.1, since it does bring a few breaking changes with custom importers and custom functions (not that many, but still noticeable). @am11 what do you think, do you have time to adjust this in node-sass before 3.0? It basically just involves setting a list of importers instead of a single one (plus passing an additional priority value on creation). Other than that everything can stay as it is.
How do custom importers work now?
For each
@import
libsass will call importers in priority order (highest priority first). If the importer returns0
, libsass will skip to the next one. If no importer returns anything, libsass will continue to load the import on its own. Once an importer returns something (either a list of imports, an empty list of imports or an error), the chain is aborted and only the given return is handled. Additionally I fixed the behaviour when only a filename is returned to be exactly as with plain libsass imports.Breaking C-API changes
To create custom importer list:
New function signatures for custom functions and importers:
The options that have previously been passed can now be fetched indirectly:
You should now be able to access all context options via API calls.
Renamed a lot of typedefs regardings function and importer API. They should now make much more sense. Not sure how big of an impact this has on implementers though, but it should make it a lot more future-proof. Signatures for functions and importers should not need to change again, since they can now access all options available indirectly via the passed arguments.
Renamed structs/typedefs (probably incomplete):
New experimental feature
Custom headers (#960) act like importers, but only run once at the beginning of each compilation. They are primarily meant to define custom mixins (via plugins or context options). Beside that they might be usefull for other cool things I currently cannot think of 😄 Opposite to custom importers, all custom headers will be executed in priority order and all imports will be accumulated (so many custom headers can add various custom mixins or css-code).
Include in 3.2.0 !?
From a strict versioning stand-point, this should be included in 3.2 since it contains quite a few breaking changes in the API. The new plugins API would also benefit from it. Adding it to 3.2.1 seems wrong and since it is only stabilizing experimental features, I re-scope this to 3.2 (open for further discussions). I touches quite some code though to be added that late in the beta phase. IMO we should do at least another beta round to let node-sass catch-up to these changes.
//CC @xzyfer @am11 @chriseppstein