Grunt實現前端自動化

定義:我的認爲,前端自動化就是便捷地將開發代碼迅速轉化爲發佈代碼的過程。javascript

 

意義:通常來講,開發代碼不會直接部署上線運行,小型項目倒問題不大,但對於大型項目來講,要考慮到服務器的壓力以及保密的等緣由,須要將代碼的體積最小化,減小請求數量,對代碼進行混淆和壓縮,若是手動完成這個過程,會比較繁瑣。css

 

主要用到的技術:Grunt(首先要安裝Node.js環境,安裝好Node.js環境至關於安裝好了npm,在項目建設過程當中就是用npm下載各個JS庫的)html

 

範例步驟:前端

1、先看看整個項目文件結構(假定咱們已經實現了src以及image文件夾下的全部內容java

這個項目實現的功能是隨機顯示一個顏色做爲網頁背景,並隨機顯示一個0~100的數字。node

傳統的網頁項目只會有名爲src和image文件夾下的內容(忽略名爲concat的兩個文件夾以及文件夾下的內容,這兩個文件夾只是在生成過程當中的一個副產品^_^),真正部署時用到的是名爲dist以及image的文件夾。jquery

個人HTML文件是這樣的,引用了兩個js文件和一個css文件:npm

<!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>

 

 

2、定義項目相關信息(package.json)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格式。segmentfault

所展現的這個文件依次定義了npm包名、版本號、描述、入口文件、腳本說明對象、做者、只在開發時須要的依賴包、當前包所需的依賴包,固然這個文件還可有別的參數,具體能夠參考這裏或者這裏

ps:之因此到處與npm相關,是由於基於grunt其實等於基於npm,而npm自己就是爲了開發者開發各類JS庫所誕生的「包管理工具」。

若是一開始項目沒有這個文件,能夠經過控制檯執行npm init,而後根據提示一步一步生成這個文件。

其中dependencies下的條目其實都不是手打的,實際上是能夠自動生成的,具體看下一步。

 

3、安裝依賴包(我所理解的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文件夾下就會出現截圖中所出現的依賴包了。

 

4、建立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是定義一個任務的執行過程(固然它不只僅只能這樣作,還能夠有更多功能和更多寫法,暫且這樣認爲吧)

 

5、執行

在控制檯中執行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來描述的,半天反應不過來是指這樣的東西。。

沒留意裏面貼出的代碼段,也沒想到竟然一個註釋都能有這樣的功能。。

相關文章
相關標籤/搜索