grunt打包实践

目的

学会grunt打包
并将grunt打包运用于项目实践

前提

  • 了解 grunt 的作用与用途
  • 熟悉 nodejs
  • 熟悉npm的用法

工具链

grunt 安装

由于我们在开发web项目的时候,都要用 grunt 打包,为了减少重复操作,所以需要安装 grunt 到全局,具体的安装脚本如下:

1
npm i grunt grunt-cli -g //安装grunt到全局

less 安装

由于在项目开发的过程中,我们用到了less,所以提交安装less到全局,具体的安装脚本:

1
npm i less@latest -g //安装less到全局

流程

打包流程

配置

准备 Grunt 项目

一般需要在你的项目中添加两份文件:package.jsonGruntfile
package.json: 此文件被npm用于存储项目的元数据,以便将此项目发布为npm模块。你可以在此文件中列出项目依赖的gruntGrunt插件,放置于devDependencies配置段内。
Gruntfile: 此文件被命名为 Gruntfile.jsGruntfile.coffee,用来配置或定义任务(task)并加载Grunt插件的。 此文档中提到的 Gruntfile 其实说的是一个文件,文件名是 Gruntfile.jsGruntfile.coffee.

配置 package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"name": "angularjs-e2e-showcase", //项目名称
"version": "1.0.0", //版本号
"private": true, //
"devDependencies": { //开发依赖
"grunt-contrib-clean": "0.6.0", //清楚目录或者文件
"grunt-contrib-jshint": "0.11.0", //js语法检查
"grunt-contrib-concat": "0.5.1", //合并
"grunt-contrib-uglify": "0.8.0", //js压缩
"grunt-contrib-watch": "0.6.1", //监听
"grunt-contrib-cssmin": "0.13.0", //css严肃哦
"grunt-filerev": "2.3.1", //文件重命名
"load-grunt-tasks": "3.2.0", //加载grunt任务
"grunt-usemin": "3.0.0", //
"grunt-contrib-copy": "0.8.0", //拷贝
"grunt-contrib-imagemin": "0.9.4", //生成雪碧图,并对css相关样式做出调整
"karma-coverage": "0.4.2", //
"grunt-lesslint": "1.4.1", //less检查
"grunt-contrib-less": "~1.0.1", //less生成工具
"grunt-contrib-htmlmin": "0.6.0", //html压缩
"karma-jasmine": "0.3.6", //
"busboy": "^0.2.9", //
"fs-extra": "^0.16.4" //
} //

安装依赖包,安装命令
npm i
如果是国内的话,可以使用 taoao的npm安装源

1
2
3
npm i nrm -g
nrm use taobao
npm i

建立 Gruntfile 文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
* Created by david on 4/10/2016.
*/
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt); //加载 load-grunt-tasks grunt插件
//定义路径变量
var path = {
tmp: '.tmp', //临时目录
dest: '.publish', //发布目录
web: '' //项目站点
};
//项目配置文件
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
path: path, //申明变量
//清楚文件和目录
clean:{
},
//编译less文件为css
less:{
},
//生成雪碧图,并修改相应的css文件
sprite:{
},
//拷贝文件
copy:{
},
//合并文件
concat:{
},
//压缩css
cssmin:{
},
//压缩Js
uglify:{
},
//文件重命名
filerev:{
},
//替换文件前准备
useminPrepare:{
},
//替换文件
usemin:{
}
});
grunt.registerTask(
'build', //分组名称
[ //该分组包含的任务
'clean:beforebuild',
'less',
'sprite',
'copy',
'concat',
'cssmin',
'uglify',
'filerev',
'useminPrepare',
'usemin',
'clean:afterbuild'
]
);
};

清除文件目录

该任务包含两个子任务:

  • 构建前执行脚本
    清除 dest,与 tmp 相关目录与文件

    1
    2
    3
    4
    5
    beforebuild: {
    files: [{
    src: ['<%= path.dest %>/', '<%= path.tmp %>/']
    }]
    },
  • 构建后执行脚本
    清除 tmp 相关目录与文件

    1
    2
    3
    4
    5
    afterbuild: {
    files: [{
    src: ['<%= path.tmp %>/']
    }]
    }

编译less文件

1
2
3
4
5
6
7
8
9
baseStyleCss: {
options: {
strictMath: true,
sourceMap: true,
outputSourceFiles: true
},
src: 'content/stylesheet/less/config.less', //该less文件将导入其他的less文件
dest: 'content/stylesheet/css/config.css'
}

生成雪碧图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
options: {
// 给雪碧图追加时间戳,默认不追加
spritestamp: true
},
// image-set 示例
imageKityMinderSprite: {
options: {
useimageset: true,
imagepath: "content/images/slice/", //less文件应用图片的目录地址
spritedest: '<%= path.tmp%>/images/slice/' //生成后的雪碧图目录地址
},
files: [{
// 启用动态扩展
expand: true,
// css文件源的文件夹
cwd: 'content/stylesheet/css',
// 匹配规则
src: '*.css',
// 导出css和sprite的路径地址
dest: '<%= path.tmp%>/css/',
// 导出的css名
ext: '.sprite.css'
}]
}

拷贝文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fonts: { //拷贝字体
expand: true, //展开
cwd: 'content/fonts/', //改变当前路径
src: ['**'], //匹配文件的正则表达式
dest: '<%= path.dest %>/fonts/', //
flatten: false //
}, //拷贝图片
images: { //
expand: true, //
cwd: 'content/images/other', //
src: ['**'], //
dest: '<%= path.dest%>/images/other', //
flatten: false //
}, //拷贝雪碧图
spriteImages: { //
expand: true, //
cwd: '<%= path.tmp%>/images/slice', //
src: ['**'], //
dest: '<%= path.dest%>/images/slice', //
flatten: false //
}, //拷贝站点小图标
ico: { //
src: 'favicon.ico', //
dest: '<%= path.dest%>/' //
}, //
indexCopy: { //拷贝index.html
expand: true, //
src: ['index.html'], //
dest: '<%= path.dest%>/', //
flatten: false //
}, //
appViewsCopy: { //拷贝应用相关html文件
expand: true, //
cwd: 'app/', //
src: ['**/**.html'], //
dest: '<%= path.dest%>/app/', //
flatten: false //
} //

合并文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
baseCss: { //合并css
src: [
"bower_components/bootstrap/dist/css/bootstrap.css",
"bower_components/angular/angular-csp.css",
"bower_components/color-picker/dist/color-picker.css",
"bower_components/codemirror/lib/codemirror.css",
"bower_components/hotbox/hotbox.css",
".tmp/css/config.sprite.css"
],
dest: "<%= path.tmp%>/css/showcase.css"
},
kityminderJs: {
src: [ //合并js
"bower_components/angular/angular.js",
"bower_components/jquery/dist/jquery.js",
"bower_components/bootstrap/dist/js/bootstrap.js",
"bower_components/angular-bootstrap/ui-bootstrap.js",
"bower_components/angular-bootstrap/ui-bootstrap-tpls.js",
"bower_components/seajs/dist/sea-debug.js",
"bower_components/color-picker/src/color-picker.js",
"bower_components/codemirror/lib/codemirror.js",
"bower_components/codemirror/mode/xml/xml.js",
"bower_components/codemirror/mode/javascript/javascript.js",
"bower_components/codemirror/mode/css/css.js",
"bower_components/codemirror/mode/htmlmixed/htmlmixed.js",
"bower_components/codemirror/mode/markdown/markdown.js",
"bower_components/codemirror/addon/mode/overlay.js",
"bower_components/codemirror/mode/gfm/gfm.js",
"bower_components/angular-ui-codemirror/ui-codemirror.js",
"bower_components/kity/dist/kity.js",
"bower_components/hotbox/hotbox.js",
"lib/kityminder/src/kityminder.js",
"bower_components/marked/lib/marked.js",
"app/kityminder/kityminder.app.js",
"app/kityminder/templates.js",
"app/kityminder/service/commandBinder.service.js",
"app/kityminder/service/config.service.js",
"app/kityminder/service/memory.service.js",
"app/kityminder/service/lang.zh-cn.service.js",
"app/kityminder/service/valueTransfer.service.js",
"app/kityminder/service/minder.service.js",
"app/kityminder/service/resource.service.js",
"app/kityminder/service/revokeDialog.service.js",
"app/_filter/lang.filter.js",
"app/_directive/kityminder/topTab/topTab.directive.js",
"app/_directive/kityminder/undoRedo/undoRedo.directive.js",
"app/_directive/kityminder/appendNode/appendNode.directive.js",
"app/_directive/kityminder/arrange/arrange.directive.js",
"app/_directive/kityminder/operation/operation.directive.js",
"app/_directive/kityminder/hyperLink/hyperLink.directive.js",
"app/_directive/kityminder/imageBtn/imageBtn.directive.js",
"app/_directive/kityminder/noteBtn/noteBtn.directive.js",
"app/_directive/kityminder/resourceEditor/resourceEditor.directive.js",
"app/_directive/kityminder/priorityEditor/priorityEditor.directive.js",
"app/_directive/kityminder/progressEditor/progressEditor.directive.js",
"app/_directive/kityminder/noteEditor/noteEditor.directive.js",
"app/_directive/kityminder/notePreviewer/notePreviewer.directive.js",
"app/_directive/kityminder/templateList/templateList.directive.js",
"app/_directive/kityminder/themeList/themeList.directive.js",
"app/_directive/kityminder/layout/layout.directive.js",
"app/_directive/kityminder/styleOperator/styleOperator.directive.js",
"app/_directive/kityminder/fontOperator/fontOperator.directive.js",
"app/_directive/kityminder/expandLevel/expandLevel.directive.js",
"app/_directive/kityminder/selectAll/selectAll.directive.js",
"app/_directive/kityminder/colorPanel/colorPanel.directive.js",
"app/_directive/kityminder/navigator/navigator.directive.js",
"app/_directive/kityminder/searchBox/searchBox.directive.js",
"app/_directive/kityminder/searchBtn/searchBtn.directive.js",
"app/kityminder/dialog/hyperlink/hyperlink.ctrl.js",
"app/kityminder/dialog/image/image.ctrl.js",
"app/kityminder/dialog/im-export-node/imExportNode.ctrl.js",
"app/_directive/kityminder/kityminderEditor/kityminderEditor.directive.js",
"lib/kityminder/src/expose-kityminder.js",
"app/app.module.js",
"app/kityminder/kityminder-main-controller.js"
],
dest: "<%= path.tmp%>/js/showcase.js"
}

压缩css

1
2
3
4
kopBaseCss: {
src: ["<%= path.tmp%>/css/showcase.css"],
dest: "<%= path.dest %>/css/showcase.css"
}

压缩Js

1
2
3
4
baseJs: {
src: "<%= path.tmp%>/js/showcase.js",
dest: "<%= path.dest%>/js/showcase.js"
}

文件重命名

1
2
3
4
5
build: {
files: [{
src: ['<%= path.dest %>/js/**.js', '<%= path.dest %>/css/**'] //只是对js于css重新命名
}]
}

替换文件前准备

1
2
3
4
5
html: '<%= path.dest %/**/*.html',
options: {
dest: './<%= path.dest %>',
root: './<%= path.dest %>'
}

替换文件

1
2
3
4
5
6
7
8
html: {
files: [{
src: '<%= path.dest %>/**/*.html'
}]
},
options: {
assetsDirs: ['<%= path.dest %>']
}

实例

项目地址传送门:
https://github.com/haibinpark/angular-e2etest-showcase.git

参考

Gruntjs官方网站
Gruntjs中文网站

关注链智思维导图,最新文章主动推送
关注链智思维导图(linqmind)