声明,以下相关全是前端的东西。
- Yeoman 一个自动化工作流,说白了就是把一些你需要手动操作的东西,自动给你做好。
我的理解就是给你创建一个项目,然后里面该有的东西都有了。
官网:http://www.yeoman.io/
- Grunt 什么?大G?,其实不是的。
一个类似maven的东西(不知道maven?,那总知道ant吧),能够对前端的文件进行压缩,打包,还有部署,(应该不叫部署,叫整理,更合适一些)。
官网:http://gruntjs.com/
grunt的强大,在于可以有很多第三方的插件可以下载,例如less,coffeescripe等等,grunt可以帮助你自动编译这些文件。
- Bower 一只肥鸟
,官方说法叫做A package manager for the web,也就是包管理器。
自我感觉不是很好用,比如你需要用jquery,它会把jquery相关的文件全部下载,例如jquery.cokkie.js等,不仅浪费时间,还占用空间。
下面来讲解,这三样东西的具体配置:
安装Yeoman
//首先,你可以执行 sudo npm install -g yo grunt-cli bower 这样可以一下安装3个文件,当然你也可以选择不装。。
先得安装Node.js,Git和Ruby,不要问为什么,官网说的。。。
npm install -g yo
创建一个project目录,定位在该目录下
npm install -g generator-webapp
-g 的意思是全局安装,这样的话你就可以在任何地方使用yo命令了。
默认情况下会让你选择webapp所用的框架,例如
可以多选,也可以单选,选择后生成的相关配置文件也会根据你的选择来改变,所以这一配置要慎重。
这样,yeoman就装好了。
让你想执行bower命令时,发现报错,因为你还没装bower。。
安装Bower
npm install -g bower
这个很简单,先装上再说,具体用法,下面会讲。
安装Grunt
npm install -g grunt-cli
cli并不是grunt,只是一个能够让你执行grunt命令的程序
接下来安装grunt
npm install -g grunt
回到你建的project目录,装完之后可以看到 目录下会有一个Gruntfile.js文件,
这个是grunt的核心文件,也是这三样东西交互的文件。应该是下面这个样子
// Generated on 2014-04-08 using generator-webapp 0.4.8
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
config: {
// Configurable paths
app: 'app',
dist: 'dist'
},
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['bowerInstall']
},
js: {
files: ['<%= config.app %>/scripts/{,*/}*.js'],
tasks: ['jshint'],
options: {
livereload: true
}
},
jstest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['test:watch']
},
gruntfile: {
files: ['Gruntfile.js']
},
styles: {
files: ['<%= config.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= config.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= config.app %>/images/{,*/}*'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
livereload: 35729,
// Change this to '0.0.0.0' to access the server from outside
hostname: 'localhost'
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
]
}
},
test: {
options: {
port: 9001,
base: [
'.tmp',
'test',
'<%= config.app %>'
]
}
},
dist: {
options: {
open: true,
base: '<%= config.dist %>',
livereload: false
}
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= config.dist %>/*',
'!<%= config.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: [
'Gruntfile.js',
'<%= config.app %>/scripts/{,*/}*.js',
'!<%= config.app %>/scripts/vendor/*',
'test/spec/{,*/}*.js'
]
},
// Mocha testing framework configuration options
mocha: {
all: {
options: {
run: true,
urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
}
}
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the HTML file
bowerInstall: {
app: {
src: ['<%= config.app %>/index.html'],
ignorePath: '<%= config.app %>/'
}
},
// Renames files for browser caching purposes
rev: {
dist: {
files: {
src: [
'<%= config.dist %>/scripts/{,*/}*.js',
'<%= config.dist %>/styles/{,*/}*.css',
'<%= config.dist %>/images/{,*/}*.*',
'<%= config.dist %>/styles/fonts/{,*/}*.*',
'<%= config.dist %>/*.{ico,png}'
]
}
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: '<%= config.app %>/index.html'
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/styles/{,*/}*.css']
},
// The following *-min tasks produce minified files in the dist folder
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.{gif,jpeg,jpg,png}',
dest: '<%= config.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.svg',
dest: '<%= config.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
removeCommentsFromCDATA: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
useShortDoctype: true
},
files: [{
expand: true,
cwd: '<%= config.dist %>',
src: '{,*/}*.html',
dest: '<%= config.dist %>'
}]
}
},
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= config.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= config.app %>/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= config.dist %>/scripts/scripts.js': [
// '<%= config.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'images/{,*/}*.webp',
'{,*/}*.html',
'styles/fonts/{,*/}*.*',
'bower_components/bootstrap/dist/fonts/*.*'
]
}]
},
styles: {
expand: true,
dot: true,
cwd: '<%= config.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
}
});
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('server', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run([target ? ('serve:' + target) : 'serve']);
});
grunt.registerTask('test', function (target) {
if (target !== 'watch') {
grunt.task.run([
'clean:server',
'concurrent:test',
'autoprefixer'
]);
}
grunt.task.run([
'connect:test',
'mocha'
]);
});
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'cssmin',
'uglify',
'copy:dist',
'rev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
这是系统默认生成的,当时我选择的是bootstrap。
可以看到,文件中的每个配置项都是一个task,并且每一个task都是需要下载grunt插件的。
require('load-grunt-tasks')(grunt);
这段代码很重要,他会找到项目下的node_modules文件夹,具体说应该是package.json文件,把其中的grunt插件全部引入。 所以package.json文件和node_moudles要完全对应
接下来便可以执行grunt serve命令了
执行完毕后是否看到浏览器自动打开,而且访问localhost 9000端口,如果不是,那么回去检查一下是否配置有错。
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
上面说的grunt serve命令就是上面这段代码执行的。
可以看到这个serve命令还接受一个参数target,如果执行grunt serve:dist 就会执行build task还有connect下的dist下的 keeplive task。
在这说明一下如果grunt 某个task时没有传target,会默认寻找第一个target的task。
如果不传参数,正常执行if外面的命令,最后也个watch task很关键,会启动一个临时server来给你debug用,会监听你的每个文件是否改变来刷新你的浏览器(livereload task配
置相关),很智能吧。
关于livereload可以自己百度一下,一个解放你f5的东西。
下面来介绍里面的每个task
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'images/{,*/}*.webp',
'{,*/}*.html',
'styles/fonts/{,*/}*.*',
'bower_components/bootstrap/dist/fonts/*.*'
]
}]
},
styles: {
expand: true,
dot: true,
cwd: '<%= config.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
copy task 可以看到,有两个key,dist和styles 在这声明一下,以下所有在key为dis下的task都是和build有关的,也就是只有执行build task是才会和用到这些task
files: [{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'images/{,*/}*.webp',
'{,*/}*.html',
'styles/fonts/{,*/}*.*',
'bower_components/bootstrap/dist/fonts/*.*'
]
}]
file下一般配置的就是源文件和目标文件的转换了,具体参照http://gruntjs.com/configuring-tasks
styles: {
expand: true,
dot: true,
cwd: '<%= config.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
就是一个task 名字叫做styles,目的是把styles下的css文件拷到tmp/styles下,怎么调用呢?copy:styles ,因为是自动生成的,所以感觉没啥用。
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= config.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= config.app %>/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= config.dist %>/scripts/scripts.js': [
// '<%= config.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
这段代码配置了3个task,但是为什么会被注释掉呢?
你不会看头两句话么? usemin block?
usemin block 是一种注释语言,写在你的html页面中,你可以打开index.html来查看,是不是有类似下面的
类似build:js这种,当配置过usemin之后,便可以使用他们,从而不用直接写在Gruntfile.js文件里,直接写在html页面里来执行task。。
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: '<%= config.app %>/index.html'
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/styles/{,*/}*.css']
},
具体自己看注释吧,写的的很清楚。。
rev: {
dist: {
files: {
src: [
'<%= config.dist %>/scripts/{,*/}*.js',
'<%= config.dist %>/styles/{,*/}*.css',
'<%= config.dist %>/images/{,*/}*.*',
'<%= config.dist %>/styles/fonts/{,*/}*.*',
'<%= config.dist %>/*.{ico,png}'
]
}
}
},
这个task就是为了在build时给每个引入的文件家一个时间戳来防止浏览器304用的。。 上面的英文注释,自己看吧。。
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
autoprefixed 顾名思义,就是给css里的属性加前缀的,例如 -webkit -mozila 就是这种前缀。
// Run some tasks in parallel to speed up build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
}
根据注释可以看出,这个task是为了让一些task并行执行,从而提高build的速度,一开始感觉没什么用,不过我吧这个去掉之后,build的时间还真的增加了。。
// Mocha testing framework configuration options
mocha: {
all: {
options: {
run: true,
urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
}
}
},
这个东西我从来没有成功过,看注释貌似是关于测试用的,可以我一直没有下载成功过这个插件,有兴趣的同学可以研究一下。。
其他的一些关于min的task都是压缩文件的,很容易理解,再次就不多说了。
如果你的项目需要编译coffee 和 less 等文件,你也可以配置一些task来让grunt编译,像是这样
coffee: {
dist: {
files: [{
// rather than compiling multiple files here you should
// require them into your main .coffee file
expand: true,
cwd: '<%= yeoman.app %>/scripts',
src: '{,*/}*.coffee',
dest: '.tmp/scripts',
ext: '.js'
}]
},
test: {
files: [{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.coffee',
dest: '.tmp/spec',
ext: '.js'
}]
}
},
less: {
dist: {
expand: true,
cwd: "<%= yeoman.app %>/styles",
src: "{,*/}*.less",
dest: ".tmp/styles",
ext: ".css"
}
},
coffee: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
tasks: ['coffee:dist']
},
less: {
files: ["<%= yeoman.app %>/styles/{,*/}*.less"],
tasks: ["less:dist"]
},
最后说明一下关于Gruntfile.js文件中的.tmp路径,这个路径可以理解为一个文件中转站,你的js或者css或者html等文件在执行build命令或者编译是都需要先拷贝的这个路径下来,然后在拷到dist目录,而且如果livereload配置的也是这个,就可以在watch task里自动引入.tmp下的js和css了。
如果你的项目里引入了requirejs,那么请你先下载grunt-contrib-requirejs,然后给配置文件增加一个task,像是这样
requirejs: {
dist: {
// Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
options: {
baseUrl: '.tmp/scripts',
optimize: 'none',
paths: {
// 'templates': '../../.tmp/scripts/templates',
'modernizr' : '../../app/bower_components/modernizr/modernizr',
'fastclick' : '../../app/bower_components/fastclick/lib/fastclick',
'jquery_cookie' : '../../app/bower_components/jquery.cookie/jquery.cookie',
'jquery_placeholder' : '../../app/bower_components/jquery-placeholder/jquery.placeholder',
'foundation' : '../../app/bower_components/foundation/js/foundation',
'jquery': '../../app/bower_components/jquery/dist/jquery.min',
'wow' : '../../app/bower_components/wow/wow',
'app': '../../.tmp/scripts/app'
},
// TODO: Figure out how to make sourcemaps work with grunt-usemin
// https://github.com/yeoman/grunt-usemin/issues/30
//generateSourceMaps: true,
// required to support SourceMaps
// http://requirejs.org/docs/errors.html#sourcemapcomments
preserveLicenseComments: false,
useStrict: true,
wrap: true
//uglify2: {} // https://github.com/mishoo/UglifyJS2
}
}
},
这样在build的时候,requirejs会把你的相关的js管理起来,最终build一个mian文件。
下面说一下bower
bower可以搭配这grunt一块用,在回头看上面的Gruntfile.js文件
// Automatically inject Bower components into the HTML file
bowerInstall: {
app: {
src: ['<%= config.app %>/index.html'],
ignorePath: '<%= config.app %>/'
}
},
可以看到,如果你执行这个task ,bower会自动把bower_comments下的文件里的相关js或者css全部引入,引入位置是index,html里的<!-- bower:css --> 或者<!-- bower:js -->标签内,个人感觉如果和requirejs搭配起来不太好用,不过有另外一个grunt插件grunt-bower-requirejs可以解决这个问题,可是我至今没试成功。。
最后上传一个我做的视觉滑动落差页面,有兴趣的朋友可以参考下