Front-end workflow, grunt Getting Started Guide
Posted@2013-04-20 7:15 a.m.
Categoriesgrunt, JavaScript
I want to take a moment to recall the work that needs to be done as a front end (Loading ...)
- JS Merge
- JS Compression
- CSS Compression
- CSS Sprite
- Picture optimization
- Test
- Static resource cache (version update)
- ...
Correspondingly, a fully armed front end might be like this:
- Jshint
- Csslint
- Jade
- Coffeescript
- Requirejs/seajs
- Compass/stylus/less
- Qunit/mocha/jasmine
- ...
It's such a tough set-up, but it's the tools and solutions that make our work better, WTF.
Equipped with so many weapons, the posture of the knife is very important, rushed to the embarrassment of the bad like certainly not. If each tool (Task) corresponds to a trick, grunt is used to combine a variety of gorgeous continuous technology auxiliary equipment. The metaphor is slightly white, and the notion of high-end atmospheric internationalization is called "Workflow" (Workflow). So get to the point: Grunt forging guide, see!
- Installation
- About Plugins
- Configuration tasks
- Template variables
- Task Options
- Specify file
- Compact Format
- Files Object Format
- Files Array Format
- Wildcard characters
- Dynamic Matching
- Custom tasks
Note: These are based on the grunt 0.4.x
version and require the NODEJS version>=0.8.0
Under command line installation:
# 如果之前有装过grunt,卸载之npm uninstall -g grunt# 安装grunt运行工具npm install -g grunt-cli
A grunt project requires two files: package.json
and Gruntfile.js
, the former is used for Nodejs package management, such as Grunt plug-in installation, which is grunt configuration file, configuration task, or custom task.
As a package.json
file, Sir, running in the directory of the Grunt project npm install
can generate an empty one package.json
.
Install grunt to the current directory:npm install grunt --save-dev
Regenerate into a Gruntfile.js
template file, this time can be used grunt-init, or directly handwritten one:
module.exports = function(grunt) { grunt.initConfig({ // task configuration }); // Load the plugin grunt.loadNpmTasks(‘grunt-contrib-uglify‘); // Default task(s) grunt.registerTask(‘default‘, [‘uglify‘]);});
About Plugins
Grunt use different plug-ins to accomplish different tasks, such as using UGLIFYJS compression JS corresponding plug-in is grunt-contrib-uglify
.
Use plug-ins ( grunt-contrib-uglify
as an example):
Install the corresponding plugin in the Grunt project directorynpm install grunt-contrib-uglify --save-dev
Gruntfile.js
loading the plug-in ingrunt.loadNpmTasks(‘grunt-contrib-uglify‘)
Gruntfile.js
Configure the corresponding plug-in task in, specify the JS file to compress
About configuration and how to run the task goes down the hill.
Here you can see the available plug-ins, basically most of the tasks you can think of or do not think of can find the corresponding plug-ins, need to do what to install.
Later, if you want to reuse a configuration for a grunt project, you only need to have package.json
Gruntfile.js
these two files, and then you npm install
can install all the dependent plugins.
A plugin is a task, in general, all plug-ins will follow the following will be said to the task configuration rules, many plug-in documents are not very detailed, so you can only according to the plug-in provided by the sample to apply these rules to see if there is more possibility of configuration.
About tasks
The tasks are divided into two categories: Basic tasks and the Multi tasks
Multi-tasks has the so-called target, such as the following concat
tasks foo
and bar
two targets, and the uglify
task has a bar
target called
grunt.initConfig({ concat: { foo: { // concat task ‘foo‘ target options and files go here. }, bar: { // concat task ‘bar‘ target options and files go here. } }, uglify: { bar: { // uglify task ‘bar‘ target options and files go here. } }});
The name of target can be specified arbitrarily, because target only runs the specified task with a specific configuration, such as grunt concat:foo
either grunt concat:bar
foo or the concat task specified by bar, respectively. If only the run grunt concat
will traverse all concat
the next targets run sequentially.
However, the name of the task, such as concat
uglify
fixed, is specified by the corresponding plug-in, in the plugin's use of the document will be described.
Each multi task must have at least one target.
A task that you do not need to configure is a basic task, so you can define a basic task,grunt.registerTask(taskName, [description, ] taskFunction)
// foo taskgrunt.register(‘foo‘, function(arg1, arg2) { // do something});
This runs: grunt foo
, or grunt foo:a:b
, a
and b
is foo
the argument passed to the
Template variables
Grunt can <%= k.sub.k %>
insert additional property values for a configuration by using a format similar to this
Options
In a task configuration, the option property can be used to override the default configuration, and each target can have its own option property. The option priority of target is higher than the task. options
is optional.
grunt.initConfig({ concat: { options: { // Task-level options may go here, overriding task defaults. }, foo: { options: { // ‘foo‘ target options may go here, overriding task-level options. }, }, bar: { // No options specified; this target will use task-level options. }, },});
Not all tasks will have option.
Specify file
This should be just contact grunt when the most people feel overwhelmed, think of so many plug-ins, each plug-in need to specify the corresponding to apply to the file, but I look like each plug-in has a set of their own configuration file way, configuration looks very casual, so always feel there is a trace of not reliable.
As mentioned before, there is a common set of rules:
Grunt provides several different formats for defining file mappings in the form of src-dest . These formats are supported by any multi-task.
File mappings can be in 3 formats: Compact format, files Object format, and file array format, where the "compact" and "File array" forms provide some additional properties available:
filter
Filter, accept FS. The name of the stats method definition, such as, isFile
isDirectory
or a custom function that accepts a source file name as a parameter, returns true
or false
.
nonull
Retain src Patterns Even if they fail to match files. Combined with Grunt's--verbose flag, this option can help debug file path issues.
matchBase
Patterns without slashes would match just the basename part.
...... (Leave a few to read the document)
- There's also a dynamic file list generation (batch matching file)
The property names and, in the following example src
dest
, are files
fixed key names, so you don't have to tangle at first.
Compact Format
This form only allows a single src-dest to be mapped within a target, and only src
attributes are required, and no dest
, this form is generally used in read-only tasks such as Jshint
grunt.initConfig({ jshint: { foo: { src: [‘src/aa.js‘, ‘src/aaa.js‘] }, }, concat: { bar: { src: [‘src/bb.js‘, ‘src/bbb.js‘], dest: ‘dest/b.js‘, }, },});
Files Object Format
This form supports specifying multiple src-dest for multiple targets, the property name (key) is the target file name to output, and the value is the list of source files. additional attributes are not supported
grunt.initConfig({ concat: { foo: { files: { ‘dest/a.js‘: [‘src/aa.js‘, ‘src/aaa.js‘], ‘dest/a1.js‘: [‘src/aa1.js‘, ‘src/aaa1.js‘], }, }, bar: { files: { ‘dest/b.js‘: [‘src/bb.js‘, ‘src/bbb.js‘], ‘dest/b1.js‘: [‘src/bb1.js‘, ‘src/bbb1.js‘], }, }, },});
Files Array Format
Ibid., just support extra attributes
grunt.initConfig({ concat: { foo: { files: [ {src: [‘src/aa.js‘, ‘src/aaa.js‘], dest: ‘dest/a.js‘}, {src: [‘src/aa1.js‘, ‘src/aaa1.js‘], dest: ‘dest/a1.js‘}, ], }, bar: { files: [ {src: [‘src/bb.js‘, ‘src/bbb.js‘], dest: ‘dest/b/‘, nonull: true}, {src: [‘src/bb1.js‘, ‘src/bbb1.js‘], dest: ‘dest/b1/‘, filter: ‘isFile‘}, ], }, },});
Wildcard support
Supported by the Nodejs built-in Node-glob library, these can be used in the various file configurations described above
*
Matches any character, except/
?
Matches a single character, except/
**
Matches any character, including /
, so used in the directory path
{}
Comma-separated "or" operation (no spaces after commas)
!
Exclude a match
// You can specify single files:{src: ‘foo/this.js‘, dest: ...}// Or you can generalize with a glob pattern:{src: ‘foo/th*.js‘, dest: ...}// This single node-glob pattern:{src: ‘foo/{a,b}*.js‘, dest: ...}// Could also be written like this:{src: [‘foo/a*.js‘, ‘foo/b*.js‘], dest: ...}// All files in alpha order, but with bar.js at the end.{src: [‘foo/*.js‘, ‘!foo/bar.js‘, ‘foo/bar.js‘], dest: ...}// Templates may be used in filepaths or glob patterns:{src: [‘src/<%= basename %>.js‘], dest: ‘build/<%= basename %>.min.js‘}
Dynamically generate file names
expand
Set to true
open the following options
cwd
The path specified by all src
specified files relative to this property
src
To match the path, relative to the CWD
dest
The target path prefix of the build
ext
Replace all generated target file suffixes with this property
flatten
Delete all generated dest
paths section
rename
A function that accepts a match to the file name, and matches the target location, returning a new destination path
grunt.initConfig({ minify: { dynamic_mappings: { // Grunt will search for "**/?.js" under "lib/" when the "minify" task runs files: [ { expand: true, // Enable dynamic expansion. cwd: ‘lib/‘ // Src matches are relative to this path. src: [‘**/?.js‘], // Actual pattern(s) to match. dest: ‘build/‘, // Destination path prefix. ext: ‘.min.js‘, // Dest filepaths will have this extension. } ] } }});
Custom tasks
Here to summarize some of the problems encountered
Get/Set configuration (template variable)
You can read the JSON configuration file:config: grunt.file.readJSON(‘config.json‘)
Gets the properties of the JSON object:grunt.config(‘config.key.subkey‘)
The corresponding template variable:‘<%= config.key.subkey %>‘
To set the configuration segment:grunt.config(‘config‘, ‘value‘)
Dynamically change task configuration, loop through a task
Grunt tasks are placed in a queue order, but the queue itself is executed asynchronously, so the following is not the expected output:
grunt.registerTask(‘demo‘, function() { for (var i = 0; i < 5; i++) { grunt.task.run(‘t‘); } // 期望执行完5次`t`任务之后打印输出 // 实际上会立即输出,在`t`任务开始之前 console.log(‘run after t‘); // 执行5次`t`任务之后才会执行这个`final`任务 grunt.task.run(‘final‘);});
Dynamic change task configuration can be done with template variables, because, as mentioned above, it is not possible to assign a template variable directly in the loop, but to do an extra task to accept the configuration:
// 假如有这样的一个配置t: { target: ‘some <%= param %>‘}// 在这个demo任务中需要多次调用t任务,每次都要设置paramgrunt.registerTask(‘demo‘, function() { for (var i = 0; i < 5; i++) { // 要一个额外任务去更改配置 grunt.task.run(‘t_wrapper:‘ + i); }});// 更改`t`配置并运行grunt.register(‘t_wrapper‘, function(i) { grunt.config(‘param‘, i); grunt.task.run(‘t‘);});
There is also a way to clone a new target and then change the configuration of this cloned target directly
The difference between Grunt.config and grunt.option
grunt.config
As mentioned above can be used to dynamically change template variables, but grunt.option
not so, if used directly in the configuration, it is grunt.option
option
determined at run time, can not be changed, assuming this configuration:
t: { target: ‘some ‘ + grunt.option(‘param‘)}
Run grunt t --param=0
, the target corresponds to ‘some 0‘
this, and you can no longer grunt.option(param, 1)
change the configuration
grunt.option
And grunt.config
both can be used to share some information between tasks, but option
more to accept additional task parameters.
Set Output text color
Point a color directly behind the string:grunt.log(‘test color‘.green)
References
- Grunt API
- Gruntjs
- Workflow-vips
If you are already familiar with grunt, you can go to see Yeoman, perhaps to provide you with more inspiration.
Grunt Getting Started learning