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

Build systems > Grunt #2

Open
addyosmani opened this issue Dec 26, 2013 · 36 comments
Open

Build systems > Grunt #2

addyosmani opened this issue Dec 26, 2013 · 36 comments
Assignees
Labels

Comments

@addyosmani
Copy link
Member

A chapter on getting started with the Grunt.js task runner. The common things I see front-enders new to Grunt trying to do include:

  • Getting started (Gruntfile, package.json)
  • Adding a linter
  • Integrating a CSS preprocessor (Sass, Less)
  • Starting a local server
  • Live reload (maybe)
  • Running tests
  • Housekeeping (clean, best practices for matchdep etc)
  • Deployment

These topics could be useful to cover.

@addyosmani
Copy link
Member Author

@belen-albeza I don't suppose you'd be interested in getting involved with this chapter? :) Absolutely loved your work on the mini Grunt book, which captures quite a lot of the above in a very succinct manner.

The pitch: we're working on a free, open-source book on modern front-end tooling and want to try capturing a solid walkthrough for beginners on tools like Grunt, Yeoman and Bower etc. The book would be kept up to date by the community and offered up in multiple formats for free. We'd also happily link to author sites/pages where they have other books they'd like to mention.

@sindresorhus
Copy link
Contributor

// @kahlil

@jrcryer
Copy link

jrcryer commented Dec 27, 2013

The housekeeping / best practises is a must have. Seeing the usage of grow on a project from something rather trivial (CSS preprocessor) to becoming the main build tool (cleaning, generating and testing), I think demonstrating how to keep your Gruntfile clean / modular would be excellent.

@addyosmani
Copy link
Member Author

I think keeping your Gruntfile clean is going to be pretty important for sure. @jrcryer have you had much experience with modular (multi-file) Gruntfiles?

@jrcryer
Copy link

jrcryer commented Dec 27, 2013

@addyosmani yeah - the main product I work at the moment has multiple grunt files, we've stripped back all paths (e.g. externalising paths) to keep things clean, maintainable and readable. I'll get the other blog post written in the next couple of days for you to take a look at.

@kahlil
Copy link

kahlil commented Dec 27, 2013

@sindresorhus thanks for ccing me 😄

@addyosmani those are all definitely important points for beginners. Here are a few points I see that would be important as well:

  • how to deal with common Grunt errors thrown in the command line, what do they mean
  • how to use Yeoman or grunt-init to generate a Gruntfile and a package.json
  • how to use watch
  • how to copy a file or files with Grunt (I have seen this been mentioned as a problem for beginners multiple times)
  • how to use grunt-shell or grunt-bg-shell to integrate any shell command into a grunt build (I have seen this question come up multiple times in irc)
  • maybe as a bonus chapter: how to author a simple plugin + plugin authoring best practices (keep small, search on npm first before you start writing etc.)

Also for reference there is a lot to learn from how @chriscoyier wrote his article about Grunt for Beginners: http://24ways.org/2013/grunt-is-not-weird-and-hard/ he brought so many people to Grunt who have absolutely no experience with the command line its insane. It's his audience too of course but he definitely created a lot of understanding. So many people were raving about the article on Twitter weeks after it was published (I have access to the Grunt Twitter account and was absolutely amazed by the amount of @-replys coming in in response of that article.) It would be fantastic if @chriscoyier could give feedback on that book. I think we as devs who work with Grunt all the time often lack the understanding of how basic we actually have to go in order to explain Grunt or other tools to newbies.

on the multi-file Gruntfiles: @drublic just authored a nice little article about that on @thenittygritty: http://thenittygritty.co/shared-grunt-configuration //cc @jrcryer

@kahlil
Copy link

kahlil commented Dec 27, 2013

PS: I just saw that node and npm is already in the Outline of the book, so I'm removing it from my suggestions 😄

@belen-albeza
Copy link
Contributor

@addyosmani Hi, I'd love to write about Grunt :)

+1 to most of what @kahlil outlined, specially the part of watch and copy files. I'm not very sure about the part of authoring your own Grunt plugin, since if you need to do that, it's not that hard and Grunt's documentation on that matter is sufficient IMHO.

I would add a section of why having automation in your project is useful, and why to use Grunt instead of a bunch of shell scripts.

@jrcryer
Copy link

jrcryer commented Dec 27, 2013

@belen-albeza 👍 on why having automation in your project is useful.

Thanks @kahlil. Thoughts on use of external variable configuration? Allows for high re-use across projects - it'll form part of my post I'm writing at the moment.

@addyosmani
Copy link
Member Author

@kahlil Great points!

how to deal with common Grunt errors thrown in the command line, what do they mean

+1. A troubleshooting / errors section would be ace.

how to use Yeoman or grunt-init to generate a Gruntfile and a package.json
how to use watch

There's currently a Yeoman chapter planned but I do think we should also talk about grunt-init and the common templates used there.

how to use grunt-shell or grunt-bg-shell to integrate any shell command into a grunt build (I have seen this question come up multiple times in irc)

Interesting! I haven't seen this asked as often but if it's common enough by all means let's cover it.

maybe as a bonus chapter: how to author a simple plugin + plugin authoring best practices (keep small, search on npm first before you start writing etc.)

Many of the tools currently listed offer a form of extension authoring (Grunt tasks, Yeoman generators, Gulp plugins etc). As a P2, it would be really interesting to capture how to write your own in a straight-forward guide tacked to the end of each chapter. Perhaps we could explore this once the basic content has been authored?

The Grunt article by @chriscoyier

I thought it was incredibly succinct and although it touched upon a lot of the same intro topics we've seen covered in other Grunt articles before, the way it was presented made it SUPER easy for beginners to understand. I think striving for this in the Grunt chapter would be a great idea.

@addyosmani
Copy link
Member Author

@belen-albeza that would be incredibly kind and welcomed :) Do you think you would be looking to repurpose some of your existing content or writing something new? Either would be a really great addition to the project.

I would add a section of why having automation in your project is useful, and why to use Grunt instead of a bunch of shell scripts.

Do you think this should be the intro to the build system tooling section? I think the same argument could be made for Gulp and Brunch and ultimately there's going to be a lot of cross-over in the answers for these tools vs shell scripts imo.

@addyosmani
Copy link
Member Author

@jrcryer do you have a repo/sample of how you're approaching external variable config?

@kahlil
Copy link

kahlil commented Dec 27, 2013

Good stuffz 😺 let me just //cc @cowboy here would love to see if he has any input.

@addyosmani +1 on your comments! Authoring section in P2 makes sense. Also I think the philosophical reasoning about why to use build tools should be in the general intro for the build tool section I think.

@kahlil
Copy link

kahlil commented Dec 27, 2013

The comments on the Why Grunt? article kinda hilarious, most of the comments I see are from people that say things like "Why should I use Grunt if I can just blablablab script blab poywefjsdf pipe into blababababla". Ultimately this discussion is useless in my mind and doesn't belong on that page.

I think it's much more important to work hard to lower the barrier of entry through documentation as far as we can (like Chris did with his article). And cater to the people who are actually really looking for answers and want to relieve the pain of non-automation in their projects.

The arguments against Grunt currently are from people that don't have the barrier of entry problem and rather use scripts or Gulp (so let them use that, why even talk about it?) or are hitting against edge cases and are getting angry about that.

The edge-case of huge Gruntfiles needs to be solved but that is most likely true for any build tool. I am sure it will be solved but I am also sure it will ultimately not be simple. And it will have to be documented or automated or whatever. Time will tell.

For now I think we need to put ourselves in the shoes of people who are afraid of the command line and try to introduce them to the joys it can bring 😄

@addyosmani
Copy link
Member Author

For now I think we need to put ourselves in the shoes of people who are afraid of the command line and try to introduce them to the joys it can bring

Agree. This needs to be the overarching focus for us. We will end up documenting caveats of the shell-scripting approach vs. modern build pipelines/task runners, but the bulk of our content is going to target beginners who just want to get started with these tools. Wayyy too many are still terrified of the command-line as you say. Let's fix that :)

@kahlil
Copy link

kahlil commented Dec 27, 2013

👍

@kahlil
Copy link

kahlil commented Dec 27, 2013

@addyosmani over at the gruntjs.com we have had quite a bit of discussion on how to do that and we came up with a Tutorial/Screencast roadmap (gruntjs/gruntjs.com#69) which I am currently working off with Ben reviewing. Maybe it makes sense to combine efforts here to cover the single tutorials, the screencasts and the book and cross-link that all together. Make it sync up.

What do you think @Benalman?

@belen-albeza
Copy link
Contributor

@addyosmani I was thinking on writing something new (I'll probably reuse some of the code). IMHO it makes sense to try to have an homogeneous style through the book, instead of making it just a collection of scraps available somewhere else.

Do you think this should be the intro to the build system tooling section? I think the same argument could be made for Gulp and Brunch and ultimately there's going to be a lot of cross-over in the answers for these tools vs shell scripts imo.

+1

@addyosmani
Copy link
Member Author

IMHO it makes sense to try to have an homogeneous style through the book, instead of making it just a collection of scraps available somewhere else

Agree and that sounds awesome. I'll open up another issue to discuss style (tone, narrative, code etc).

@jrcryer
Copy link

jrcryer commented Dec 28, 2013

@addyosmani can't share our actual configuration but I've pulled together a subset of how we do it. Our actual Gruntfile is much larger. Due to a rigid structure that gets imposed on a project (outside of the scope of the team) we have to do a lot of copying and replacing with grunt itself to optimise our workflow. Pulling the paths out of the main grunt file into a single configuration object has worked well for us.

In reality we also have other configuration for things like requirejs which when placed into the Gruntfile just make it unmaintainable.

I've setup a demo:

https://github.com/jrcryer/sample-grunt-external-vars

Main files:
https://github.com/jrcryer/sample-grunt-external-vars/blob/master/config/paths.json
https://github.com/jrcryer/sample-grunt-external-vars/blob/master/Gruntfile.coffee#L8

Thoughts?

@simshanith
Copy link

This may not be the place to have this discussion, but one thing I've recently found useful when maintaining a sizeable Grunt file is to break out configuration into submodules that dynamically config a passed grunt instance, and loading those configuration modules as a task.

Modularization for separation of concerns is especially helpful when working with grunt-concurrent, and multiple grunts are spawned. With Configuration as a first-class Grunt citizen (task), I can build chains for e.g. markup, scripts, and styles that load an initial config for a subset of tasks, then selectively bootstrap more task configuration. Each parallelized process gets only the config it needs for optimal independent performance.

There are always gotchas when dealing with concurrency, tho, and stuffing config in dynamically loaded files can be trickier to debug without care.

Essentially, my grunt.initConfig() doesn't contain every loaded grunt task. Some configs are left out, e.g. jade, stylus, uglify for markup, styles, and scripts; respectively. This means I can't run grunt jade:compile directly, but instead have grunt loadConf:markup jade:compile. This is a major caveat, but in practice is largely avoided by the custom grunt markup task, which is registered in the Gruntfile and handles chaining all markup related tasks with the appropriate config. Plus, dynamically loading the markup config means my styles task won't have to. All the data I want to pass my templates won't slow down my CSS preprocessing or JS uglification.

Another bonus of Configuration as a Task: my watch will load configuration changes without restart. Meaning, I can configure some markup tasks, run watch:markup, decide I want to change some task options (e.g. Jade pretty output) and the new config will be automatically built. This works because configuration is loaded at runtime as a task.

Gruntfile went from a ~400 lines to ~260 lines. One utility module to extend grunt config at 24 lines; 3 task config JSON files at ~50-70 lines each; and 3 task modules that read the JSON, extend the config, and handle anything else as necessary at 7 lines for scripts & styles (boilerplate), while markup loads some extra Jade data & functionality to weigh in at 16 lines.

I hope to make some of this stitching together of things publicly available soon.

tl;dr

So, my 2 cents for housekeeping gruntfiles are: configuration as a task; separate your concerns.

@wilmoore
Copy link
Contributor

The edge-case of huge Gruntfiles needs to be solved but that is most likely true for any build tool.

Indeed…this is solved for most well-known and mature build tools. For example, make has a feature called recursive make. Each segment of the build is separated into sub directories which can be run recursively from the top or individually via the specific directory.

I am sure it will be solved but I am also sure it will ultimately not be simple.

To be honest, it is very simple…in fact, it is less than 20 lines of code:
https://github.com/wilmoore/require-grunt-configs

Seems like this should have been built-in; however, it pretty much was since the bulk of the work is done with grunt.file.recurse which is a documented and supported API call.

@kahlil
Copy link

kahlil commented Jan 2, 2014

Hey @wilmoore thanks for the clarifications!

I was not aware of require-grunt-configs. I like it!

If you really have a massive Gruntfile though, you may want to only load Grunt tasks as they are needed just before you run that task. The loading of the Grunt tasks is a huge time suck if you have a lot of them.

You can use this pattern to avoid the bulk-loading: https://gist.github.com/distilledhype/90dc341fb67a914d0988. Maybe require-grunt-configs could do this by default? Wrap the config in a custom task that loads the task...

@wilmoore
Copy link
Contributor

wilmoore commented Jan 2, 2014

You can use this pattern to avoid the bulk-loading

Nice! 👍

As far as adding the pattern to require-grunt-configs as a default; I'll take a look at whether the slow loading tends to be a common case or not. If it turns out to be common, then I could see adding something like this.

@kahlil
Copy link

kahlil commented Jan 2, 2014

It is definitely a problem, when you use imagemin or something like that. I just found this: https://github.com/NickHeiner/lazy-grunt-loading

@wilmoore
Copy link
Contributor

wilmoore commented Jan 2, 2014

I just found this: https://github.com/NickHeiner/lazy-grunt-loading

I like this since I'd prefer to keep the solutions separate.

Seems like one could choose to use require-grunt-configs and add lazy-grunt-loading when needed assuming the trade-offs (i.e. does not handle grunt.task.renameTask) are worth it.

FYI, for any further design discussion, it would be much kinder if we carry it on at https://github.com/wilmoore/require-grunt-configs/issues. :)

@kahlil
Copy link

kahlil commented Jan 2, 2014

Sounds good.

@shama
Copy link
Contributor

shama commented Jan 4, 2014

Just thought I'd chime in and share how @cowboy modularizes Gruntfiles: https://github.com/cowboy/wesbos/blob/master/Gruntfile.js

I think a lot of the auto-configuring helpers are great. But I think it's important to point out, Grunt is intended to have a declarative config. Which, IMO, makes it more accessible to those not as familiar with node.js/javascript and is likely one of the primary reasons grunt is popular.

So I think it would be better if a chapter about grunt was more about it's declarative config formats, glob patterns and file object properties (filter, rename, expand, etc) then about 3rd party auto-config helpers.

@vasilionjea
Copy link

I would be interested in contributing. I can write about how to setup a Grunt project similar to this one. In the project my Gruntfile is kept slim because I'm simply requiring each task into the config object. All the tasks are kept in a grunt/tasks/ directory.

Initially I added all the tasks in the Gruntfile but later I refactored. I did this on purpose so someone can easily see from my commits how you can go from a single Gruntfile to a folder structure of tasks. Pretty simple stuff but hopefully it can show a total beginner how to modularize tasks.

I created this GruntJS Patterns repo so I can add different patterns as I discover them. Once I've discovered a new pattern then I can write about it.

@wilmoore
Copy link
Contributor

wilmoore commented Jan 6, 2014

Just thought I'd chime in and share how @cowboy modularizes Gruntfiles

Thanks @shama -- that's a nice pattern 👍

@addyosmani
Copy link
Member Author

I'd love for @belen-albeza to take the lead on writing this chapter. Sound good? :) We can then add in other authors for topics that could use some work.

@belen-albeza
Copy link
Contributor

Sounds good to me, if everybody is OK with that. I'm creating a new issue to discuss the style/tone of the book #25

@danburzo
Copy link

Hi guys,
I have also started working on a article/book about Grunt and would love to chip in if you need any help!
http://danburzo.ro/grunt/chapters/front/
https://github.com/danburzo/grunt-recipes

@addyosmani
Copy link
Member Author

@danburzo We would absolutely love your input on this and my apologies for us taking so long to say 'yes' :) It looks like grunt-recipies (at least topic wise) covers a good chunk of the content we had hoped we would originally cover with the rest @belen-albeza's work. Would you be interested in taking a look at what we currently have and figuring out where it would make sense to complete the delta of what is missing with some of the awesome writing you've been doing? @belen-albeza would love your input on this in case you have time to collaborate with @danburzo on getting his help.

@belen-albeza
Copy link
Contributor

Hi, I'm sorry for not replying sooner! I guess that it all comes to to what we'd want the book to be like.

Here's my view:

Particularly, I don't see the Grunt chapter as an extensive collection of recipes (it is, after all, a chapter), but a "tutorial" on how Grunt works. It turns out that a great way to do just that is by showing how to apply common use cases, like Sass generation. But once you have learn how to compile Sass assets, is it really worth to talk about other assets generation (CoffeeScript, Handlebars, etc.). I don't think so, since the principles are the same. Of course, we can link out to these recipes, since they are quite frequent.

My take in this is that we should include use cases / recipes that show how to do something in Grunt (for instance, an async use case would be useful).

As I said, this is just my opinion, please let me know what you guys think.

@sindresorhus
Copy link
Contributor

@belen-albeza agreed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants