Grunt实现前端自动化

定义:个人认为,前端自动化就是便捷地将开发代码迅速转化为发布代码的过程。

 

意义:一般来说,开发代码不会直接部署上线运行,小型项目倒问题不大,但对于大型项目来说,要考虑到服务器的压力以及保密的等原因,需要将代码的体积最小化,减少请求数量,对代码进行混淆和压缩,如果手动完成这个过程,会比较繁琐。

 

主要用到的技术:Grunt(首先要安装Node.js环境,安装好Node.js环境相当于安装好了npm,在项目建设过程中就是用npm下载各个JS库的)

 

范例步骤:

一、先看看整个项目文件结构(假定我们已经实现了src以及image文件夹下的所有内容

这个项目实现的功能是随机显示一个颜色作为网页背景,并随机显示一个0~100的数字。

传统的网页项目只会有名为src和image文件夹下的内容(忽略名为concat的两个文件夹以及文件夹下的内容,这两个文件夹只是在生成过程中的一个副产品^_^),真正部署时用到的是名为dist以及image的文件夹。

我的HTML文件是这样的,引用了两个js文件和一个css文件:

<!DOCTYPE html>
<html>
<head>
    <title>Grunt--前端自动化</title>
    <!-- build:css css/App.min.css -->
    <link rel="stylesheet" type="text/css" href="css/index.css">
    <!-- endbuild -->
</head>
<body>
    <a>Grunt--前端自动化</a>
    <!-- build:js js/App.min.js -->
    <script type="text/javascript" src="node_modules/jquery/dist/jquery.min.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
    <!-- endbuild -->
</body>
</html>

 

 

二、定义项目相关信息(package.json)

{
  "name": "App",
  "version": "1.0.0",
  "description": "Grunt Page",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Mandy","devDependencies": {
    "grunt": "^1.0.1",
    "grunt-contrib-clean": "^1.1.0",
    "grunt-contrib-concat": "^1.0.1",
    "grunt-contrib-copy": "^1.0.0",
    "grunt-contrib-csslint": "^2.0.0",
    "grunt-contrib-cssmin": "^2.2.0",
    "grunt-contrib-jshint": "^1.1.0",
    "grunt-contrib-uglify": "^3.0.1",
    "grunt-contrib-watch": "^1.0.0",
    "grunt-usemin": "^3.1.1",
    "jquery": "^3.2.1"
  },
  "dependencies": {
    "grunt": "^1.0.1",
    "grunt-contrib-clean": "^1.1.0",
    "grunt-contrib-concat": "^1.0.1",
    "grunt-contrib-copy": "^1.0.0",
    "grunt-contrib-csslint": "^2.0.0",
    "grunt-contrib-cssmin": "^2.2.0",
    "grunt-contrib-jshint": "^1.1.0",
    "grunt-contrib-uglify": "^3.0.1",
    "grunt-contrib-watch": "^1.0.0",
    "grunt-usemin": "^3.1.1",
"jquery": "^3.2.1"
 } }

package.json文件会描述这个npm包的所有相关信息,包括作者、简介、包依赖、构建等信息,格式是严格的JSON格式。

所展示的这个文件依次定义了npm包名、版本号、描述、入口文件、脚本说明对象、作者、只在开发时需要的依赖包、当前包所需的依赖包,当然这个文件还可有别的参数,具体可以参考这里或者这里

ps:之所以处处与npm相关,是因为基于grunt其实等于基于npm,而npm本身就是为了开发者开发各种JS库所诞生的“包管理工具”。

如果一开始项目没有这个文件,可以通过控制台执行npm init,然后根据提示一步一步生成这个文件。

其中dependencies下的条目其实都不是手打的,其实是可以自动生成的,具体看下一步。

 

三、安装依赖包(我所理解的JS库,或许理解有误,正确称呼应为依赖包)

安装Grunt:控制台执行npm install grunt --save-dev

后面这个--save-dev参数就是生成前面dependencies下内容的关键,如果是--save-dev,就会保存到devDependencies,如果是--save,就会保存到dependencies。

依此类推,安装clean(清空文件夹)、concat(合并文件)、csslint(CSS语法检查)、jshint(JS语法检查)、cssmin(压缩CSS)、uglify(混淆压缩JS)、copy(复制文件)、useminPrepare(usemin的准备)、usemin(使用压缩后的文件)、watch(检测文件变化)。

npm install grunt-contrib-concat --save-dev
npm install grunt-contrib-csslint --save-dev
npm install grunt-contrib-cssmin --save-dev
npm install grunt-contrib-jshint --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-usemin --save-dev
npm install grunt-contrib-copy --save-dev
npm install grunt-contrib-clean --save-dev

 安装完之后node_modules文件夹下就会出现截图中所出现的依赖包了。

 

四、创建Gruntfile.js文件

module.exports = function(grunt){
    //初始化grunt 配置
    grunt.initConfig({
 
        //获取package.json的信息,也就是后面pkg变量的来源
        pkg: grunt.file.readJSON('package.json'),

        // 各插件的配置信息
        clean:{
            src:"dist/"
        },

        concat: {
            options:{
                stripBanners:true, // 合并时允许输出头部信息
                banner:'/*!<%= pkg.name %> - <%= pkg.version %>-'+'<%=grunt.template.today("yyyy-mm-dd") %> */'
            },
            cssConcat:{
                src:['src/css/*.css'],
                dest:'src/css/concat/<%= pkg.name %> - <%= pkg.version %>.css' // dest 是目的地输出
            },
            jsConcat:{
                src:[
                    'node_modules/jquery/dist/jquery.min.js',
                    'src/js/index.js'
                ],
                dest:'src/js/concat/<%=pkg.name %> - <%= pkg.version %>.js'
            }
        },
 
        csslint:{
            options:{
                csslintrc:'.csslint'
            },
            build:['src/css/*.css']
 
        },

        jshint:{
            options:{
                jshintrc:'.jshint'
            },
            build:['Gruntfile.js','src/js/*.js']
        },

        cssmin:{
            options:{
                stripBanners:true, // 合并时允许输出头部信息
                banner:'/*!<%= pkg.name %> - <%= pkg.version %>-'+'<%=grunt.template.today("yyyy-mm-dd") %> */\n'
            },
            build:{
                src:'src/css/concat/<%=pkg.name %> - <%=pkg.version %>.css',// 压缩是要压缩合并了的
                dest:'dist/css/<%= pkg.name %>.min.css' // dest 是目的地输出
            }
        },
        uglify:{
            options:{
                stripBanners:true, // 合并时允许输出头部信息
                banner:'/*!<%= pkg.name %> - <%= pkg.version %>-'+'<%=grunt.template.today("yyyy-mm-dd") %> */\n'
            },
            build:{
                src:'src/js/concat/<%=pkg.name %> - <%=pkg.version %>.js',// 压缩是要压缩合并了的
                dest:'dist/js/<%= pkg.name %>.min.js' // dest 是目的地输出
            }
        },
        copy:{
            html:{
                src:'src/index.html',
                dest:'dist/index.html'
            }
        },
        useminPrepare:{
            html:'index.html',
            options:{
                dest:'dist'
            }
        },
        usemin:{
            html:['dist/index.html'],
            js:['dist/js/20170711 - 1.0.0.min.js'],
            css:['dist/css/20170711 - 1.0.0.min.css']
        },

        //watch自动化
        watch:{
            build:{
                files:['src/js/*.js','src/css/*.css'],
                tasks:['concat','cssmin','uglify'],
                options:{spawn:false}
            }
        }
 
    });
    // 告诉grunt我们将使用插件
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-csslint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-usemin');
    // 告诉grunt当我们在终端输入grunt时需要做些什么
    // 先进行语法检查,如果没有问题,再合并,再压缩
    grunt.registerTask('default',
        [
        'clean',
        'concat',
        // 'csslint',
        // 'jshint',
        'cssmin',
        'uglify',
        'copy',
        'useminPrepare',
        'usemin',
        'watch'
        ]
    );
};

这个文件的存在是为了定义当我们在控制台执行grunt的时候所要执行的操作。

initConfig是针对各个功能模块的具体配置

loadNpmTasks是加载完成任务所需的模块

registerTask是定义一个任务的执行过程(当然它不仅仅只能这样做,还可以有更多功能和更多写法,暂且这样认为吧)

 

五、执行

在控制台中执行grunt命令,执行到以下效果时,说明代码已经生成完毕了。

此时我们可以看到dist文件夹出现在了项目中,接下来我们就只需要将dist文件夹和image文件夹拷贝到服务器上就可以运行了。

生成后的项目只依赖于一个css文件和一个js文件(image文件夹其实我并没有用到),而打开这两个文件,我们会发现css和js代码都已经被压缩成了一行。

HTML文件也变成了这样:

<!DOCTYPE html>
<html>
<head>
    <title>Grunt--前端自动化</title>
    <link rel="stylesheet" href="css/App.min.css">
</head>
<body>
    <a>Grunt--前端自动化</a>
    <script src="js/App.min.js"></script>
</body>
</html>

原本依赖的两个js也自动合并成了一个js —— 这里要隆重地说一说这个卡住我好久的问题!!!

一开始我的HTML并没有变化,说明usemin并没有起到效果?于是我为了解决这个问题找了很多资料,期间查找无果搁置了一段时间。

这几天才知道,原来是HTML文件中相应的JS或者CSS引用应该用<!-- build:js js/App.min.js --><!-- endbuild -->和<!-- build:css css/App.min.css --><!-- endbuild -->这样的一个注释括起来,之后usemin才可以正常运作。

其实官方文档已经提到过这个,但是由于是用英文Blocks来描述的,半天反应不过来是指这样的东西。。

没留意里面贴出的代码段,也没想到居然一个注释都能有这样的功能。。

 

posted @ 2017-07-26 17:47  聆道  阅读(706)  评论(1编辑  收藏  举报
页脚代码