Less.js: Support file globbing for @imports

Created on 13 Feb 2013  ·  70Comments  ·  Source: less/less.js

See: https://github.com/isaacs/node-glob,
and https://github.com/isaacs/minimatch~~ https://github.com/jonschlinkert/micromatch

I use these often in projects. It would be pretty awesome to be able to do the following and not have to specify individual files:

@import "mixins/*.less";
@import "components/**/*.less"; 

After only a few minutes of using these patterns they become second nature. It might even help with some of the other import issues.


Implemented via plugin: less-plugin-glob.

feature request medium priority up-for-grabs

Most helpful comment

Because I can't wait resolution of this issue anymore, I write plugin which does it, and use it for my projects. https://github.com/just-boris/less-plugin-glob
Less allow to create custom file loaders for @imports. I've create this one which resolves imports with globs in import path. Any feedback will be appreciated.

All 70 comments

Cool.. though node only (not browser) and don't think it will help other
issues. Could be useful I guess.. usually you would have a dependency chain
so you wouldnt want everything in alphabetical order.

Yeah, no way for the browser to know what files to request, so it seems like a non-starter.

well I wouldn't rule it out just because it would only apply for node but also I don't see it as a particularly important feature request.

@agatronic regarding the dependency chain, I was just talking to someone about that same thing at the node meetup yesterday. I think this is something that is useful for component/module libraries, mixins etc. as in the example. And yeah node only was what I was thinking.

I just read that stylus allow you to specify a directory and if you do that it looks for a index.sty - I like that.

as for importing every file in a directory, its only really useful if the files only contain mixins (no content).. because order matters. not sure thats a real-life scenario right now?

I like the index idea. That's a good way to do it.

its only really useful if the files only contain mixins (no content).

We use a lot of component-based development. Most of our Less components have zero dependency on other files. Of course order does matter in CSS and with more traditional design patterns, so I think you're right. Most people probably wouldn't use this the way I would - which mean they wouldn't use it all probably. But the stylus index idea is an interesting solution to this.

This isn't a priority but I just saw this and wanted to add it as a reference: https://github.com/chriseppstein/sass-globbing

I'm a huge Sass fan, and I use Chris Eppstein's glob importing plugin all the time (teammates who were on windows machines couldn't use it, so keep that in mind).

I've been looking for an equivalent in LESS, anyone see anything like it?

Yeah I'm a fan of this plugin for sure. I think anyone who has used globbing knows how nice it is to work with, but it's one of those things that seems "nice to have" until you actually use it. I can't imagine trying to do builds without it now. You can use assemble-less, it supports globbing (I'm one of the maintainers of it...)

Btw @josephspens I created this project yesterday for converting SASS to LESS. As a proof-of-concept, I converted the .scss files from bootstrap-sass and foundation to LESS, both examples are in the ./test/ folder. I was actually surprised at how close I got to converting all of the Bootstrap .scss files back to LESS. Try doing a diff between the converted sass files and "native" bootstrap less files (v2.3.1) - it's not feature complete, but it saves a lot of time.

If you do end up having to use LESS on a project, this might be worth checking out. For some language features, it shouldn't be hard to reverse the process to convert LESS to SASS

@lukeapage, you mentioned here https://github.com/cloudhead/less.js/issues/1181#issuecomment-13546979 that this would only be useful for mixin libs, and that was true at the time.

However, now that we have @import (reference), this feature will be useful for every stylesheet that can be referenced.

Also, I thought about the index.less concept and created a request for it: https://github.com/cloudhead/less.js/issues/1339. But I don't think these features are mutually exclusive or even necessarily related. Globbing allows for both include and exclude patterns, so you have a lot of control from the globbing patterns in the import statement itself.

I think the index.less feature would solve an entirely difference challenge, which is more like defining dependencies - really useful for modules, components, themes etc.

@jonschlinkert I agree

@lukeapage can you give me a head-start on which places in the code need to be modified (beyond tree/import/.js?), or suggestions for what I need to consider, e.g. should this be specific to node, etc.? I might give it shot.

This would be a great feature. I currently have a great big long list of stylesheets in my bundle.less file:

@import 'pages/home';
@import 'pages/login';
@import 'pages/404';
//etc

It would be useful to condense this into:

@import 'pages/*';

or similar.

Stylus allows you to do this -- @import 'partials/*.styl -- and I was using it _all_ the time. Would be very interested in having this in Less as well, to alleviate me from the tedious task of manually bookkeeping imports.

This + explicit import + non-duplicates would be really handy:

// Import specific file
@import "extras/specific.less"
// Import all others, specific file is skipped in this glob
@import "extras/*.less"

@lukeapage I'd like to do a plugin for this, can you give me some pointers on where to start? thx

Sorry Jon that I missed your first request for help, it wasn't intentional.
I think we might be best putting it in core (because a plugin would want to
override standard node file access - and you could inherit and implement
but that stops another plugin from building on top of it, unless they are
very careful), anyway I'd at least add support to core for import ing
multiple files from one import. It's possible today, the new bower plugin
does it, but it's a little bit hacky. Will be in touch.

Ha, I didn't realize I had already commented, so that makes two of us lol. no worries at all I know how it is.

might be best putting it in core

Sounds good. I'd be happy to help with that too. No worries either way.

Ok, been thinking and this is how I'd do it.

  1. Add a expandToFilelist to abstract file manager. By default it should
    return an array containing the filename it's given. Not sure if it should
    be synchronous or asynchronous - probably doesn't matter - make it async?
  2. In import manager, call that function once you have a file manager. Then
    loop through all files and do on each what you were doing on 1.
  3. I'd have import manager wait till it had the results from all files
    before calling back to the call back (which is in import visitor) that way
    we can maintain a consistent ordering. The call back would now take an
    array containing all the arguments (e.g full filename must be received once
    per file).
  4. There might be complications in import visitor around the context - not
    sure
  5. An import will now take an array of roots (or maybe an array of roots
    and filenames). It will need to eval all roots in its eval function and
    return a combined root.. or maybe create a new rulesets using an array of
    the evald roots, if that works
  6. Compile and test - should all work
  7. Change node file manager to implement expandToFilelist if the filename
    contains *
  8. Add tests and add tests to the excludes in the Jasmine section of the
    gruntfile, since we cannot implement for browser
    Voila!

Just wanted to comment, as a workaround, you could use gulp with gulp-concat if you're using gulp as your build tool.

gulp.src([
    'src/styles/main.less'
    ,'src/controls/**/*.less`
])
.pipe(concat('bundle.less')
.pipe(less())
...

This is effectively my directory structure... (though, my structure is a little different). I was hoping this was a built-in feature, as even if node-only would be very useful.

Just thought I'd +1 here... its a pretty common pattern. There's also several easy workarounds for avoiding the order problem.

+1

I didn't say it, but I'd appreciate the option (even if server-side only)...

oh the irony here (library primary became js because the same library could then be used server and client, only to add a server-only feature).

The parsing engine can retain parity. That's still a huge advantage that has nothing to do with what we're discussing.

+1

As if there aren't enough already: +1

+1 seriously

+1

:+1:

+1

+1

+1

+1

:+1: please!

+1 jesus would be happy with wildcard support.

Hey folks, the feedback is great, but +1s aren't going to make this feature happen any faster. It's marked as ready to be implemented, and when someone implements it, it will be implemented.

+1 jesus would be happy with wildcard support.

I think it's safe to say that if Jesus were to choose a preprocessor, it would be Less.

Because I can't wait resolution of this issue anymore, I write plugin which does it, and use it for my projects. https://github.com/just-boris/less-plugin-glob
Less allow to create custom file loaders for @imports. I've create this one which resolves imports with globs in import path. Any feedback will be appreciated.

@just-boris Hi, I was wondering how I could install this other than by NPM,

I'm getting the follow errors when using NPM:

npm ERR! 404 'less-glob-plugin' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, or http url, or git url.

Thanks in advance, this would save a great deal of heartache.

@tonyflp, sorry, there was a typo, you should install less-plugin-glob.
Less only accepts plugins named in less-plugin-* notation

@just-boris That worked great, thanks for this.

No update for this feature?

just-boris i use grunt-contrib-less they have a example how to load plugin's like this:

plugins: [
new (require('less-plugin-autoprefix'))({browsers: ["last 2 versions"]}),
new (require('less-plugin-clean-css'))(cleanCssOptions)
],

How would i load your wonderfull plugin in here so that it works with grunt-contrib-less?

Big :+1: for the feature

@vospascal answered in my repo

;) thnx @just-boris i saw :-) :+1:

Still waiting for this feature :+1: . Thanks, @just-boris.

@just-boris thanks! В смысле, спасибо :-)

This would be a very useful feature for me, since I prefer to bundle all my components in once place, rather than having all Less files in a single location. This leads to Less files existing all over the place, which would be a nightmare to maintain a manual list of imports for.

For anyone using Gulp to build their Less files, I've had success using the gulp-inject plugin to automatically create the @import statements in my main Less file. I did a short write-up of it here: http://www.michaelbromley.co.uk/blog/425/automatic-import-of-lesssass-files-with-gulp

For globbing in less you can simple simple run this in your project,

npm install less-plugin-glob --save-dev

then add this to your Gruntfile in the options group of your less task

plugins: [require('less-plugin-glob')]

The result is something like this:

···
options: {
    compress: true,
    yuicompress: true,
    optimization: 2,
    cleancss: true,
    sourceMap: false,
    sourceMapFilename: 'css/maps/style.css.map',
    plugins: [require('less-plugin-glob')]
},
···

Now in your .less file you can write this:

···
@import "commons/**/*";
@import "basic/**/*";
···

Came here wondering if glob imports were supported, but since I'm using a couple of one-liner shell scripts instead of grunt/gulp for my build process. I ended up just using find & cat and my source stays cleaner than any of the alternatives. Less continues to be awesome.

# src/index.less + src/foo/bar.less + ... = dist/index.css
find -X src -type f -name '*.less' | xargs cat | lessc - | cleancss --s0 >dist/index.css

+1

Really surprised this hasn't happened by now. Gulp has support for this feature at least.

@davidcalhoun Read the first post in this thread.

Same, as far as I am aware, most people are compiling their LESS files into CSS , I don't know of many sites that are having the browser interpret the LESS directly? For those that wish to debug, can use source maps

@just-boris I can't get your plugin to work... I assume I'm doing something wrong.

Has anyone else gotten it to work?

Not getting any errors... just no output when I try to use globbing.

gulp.task( 'styles', () => {
  return gulp.src( [ 'app/styles/main.less' ] )
    .pipe( $.less( {
      plugins: [ require( 'less-plugin-glob' ) ],
    } ) )
    .pipe( gulp.dest( 'dist/styles' ) );
} );
// main.less
// Each line below is tried on it's own of course.
@import "app/module/waffle.less"; // Works
@import "app/module/**"; // Does not work.
@import "app/module/**/*"; // Does not work.
@import "app/module/**/*.less"; // Does not work.

@SpencerCarstens It's better to raise the issue at the plugin own repository.

@seven-phases-max :+1:

I was hoping to reach a greater audience, but you are right.

@seven-phases-max You can't integrate the glob-plugin inside less?

It integrates fine, but doesn't seem to do anything.

If I comment out the plugin, my less correctly errors on the import
globing.

When I put it back in, the error stops.

So, I assume it's doing something.

On Wednesday, August 5, 2015, Mattia Astorino [email protected]
wrote:

@SpencerCarstens https://github.com/SpencerCarstens You can't integrate
the glob-plugin inside less?


Reply to this email directly or view it on GitHub
https://github.com/less/less.js/issues/1181#issuecomment-128262749.

Cordially,

Spencer Carstens

@equinusocio

You can't integrate the glob-plugin inside less?

If you mean "why to not put this into the core"... Then, well, the current Less approach (less or more set up in several discussions across various threads here) is roughly: "never put a feature to the core, _before_ it becomes absolutely and totally evident the feature belongs there and there's no other ways". That is, if something can be implemented as a plugin it _should_ be implemented as a plugin (that's why for example even long-living-in-the-core clean-css facility was moved from the core to the corresponding plugin).

@seven-phases-max ok, thanks. I like this.

Closing as implemented in @just-boris 's plugin.

+1

+1

Talk about resurrecting old threads

What are these +1's supposed to indicate? Is the plugin not workable?

The +1 indicates that you want or support it too

Support what? That's what I'm saying. This has been addressed and the issue is closed. So I'm asking what is being +1'd?

I've been getting these emails for over 2 years what's the deal here..

Was this page helpful?
0 / 5 - 0 ratings