使用gulp解決RequireJS項目前端緩存問題(一)

一、前言

使用gulp解決RequireJS項目前端緩存問題(一)javascript

使用gulp解決RequireJS項目前端緩存問題(二css

 

前端緩存一直是個使人頭疼的問題,你有可能見過下面博客園首頁的資源文件連接:html

 

有沒有發現文件名後面有一串不規則的東東,沒錯,這就是運用緩存機制,咱們今天研究的就是這種東西。前端

先堵爲快,猛戳連接下載Demohttps://github.com/hua126mail/gulpRequireJsCachejava

以dist爲根目錄,運行http://localhost/html/index.html,若是出現「Good!成功加載index.js」,則表示成功了。node

 

不熟悉gulp的同窗,能夠參考這個比較詳細的教程:http://www.ydcss.com/archives/18git

不熟悉RequireJS的同窗,能夠參考官方教程:http://www.requirejs.cn/github

 

二、項目主要目錄:

  gulpRequireJsCache
  |
  |-- dist          //存放發佈的文件
  |
  |-- rev          //存放控制版本號的 rev-manifest.json
  |
  |-- src          //項目源文件
  |
  |-- gulpfile.js     //gulp主文件,定義的任務都在這裏
  |
  |-- package.json    //gulp依賴包配置文件
  |
  |-- landing.html

  根據執行命令npm install --save-dev後,主目錄下會多一個node_modules文件夾,至此,gulp基本配置完成。

  gulpfile文件:
var gulp = require('gulp'),
    sass = require('gulp-sass'),                        //編譯sass
    cssmin = require('gulp-clean-css'),                    //壓縮css
    autoprefixer = require('gulp-autoprefixer'),        //添加瀏覽器前綴
    rev = require('gulp-rev'),                            //添加版本號
    revCollector = require('gulp-rev-collector'),        //添加版本號
    clean = require('gulp-clean'),                        //清理文目標文件夾
    csso = require('gulp-csso'),                        //合併css屬性
    csslint = require('gulp-csslint'),                    //css語法檢查
    csscomb = require('gulp-csscomb'),                    //css 樣式表的各屬性的順序
    imagemin = require('gulp-imagemin'),                //圖片壓縮
    cache = require('gulp-cache'),                        //緩存處理
    htmlmin = require('gulp-htmlmin'),                    //壓縮html
    replace = require('gulp-replace'),                    //替換路徑
    uglify = require('gulp-uglify'),                    //壓縮js
    jshint = require('gulp-jshint')                        //js語法檢查
;

gulp.task("cleanCss",function(){
    return gulp.src('dist/css',{read:false})
    .pipe(clean());
});

gulp.task('sass', ['cleanCss'],function () {            //執行完cleanCss任務後再執行sass任務
      gulp.src('src/sass/**/*.scss')
    .pipe(sass())
    .pipe(cssmin())
    .pipe(autoprefixer())
    //.pipe(csscomb())
    .pipe(csso())
    .pipe(csslint())
    .pipe(rev())
    .pipe(gulp.dest('dist/css'))
    .pipe(rev.manifest())//- 生成一個rev-manifest.json
    .pipe(gulp.dest('rev/css'));
    
});

gulp.task("cleanImg",function(){
    return gulp.src('dist/img',{read:false})
    .pipe(clean());
});

gulp.task('imgmin',['cleanImg'], function () {
    gulp.src('src/img/**/*.{png,jpg,gif,ico}')
        .pipe(cache(imagemin()))                        //沒有修改的圖片直接從緩存文件讀取
        .pipe(rev())
        .pipe(gulp.dest('dist/img'))
        .pipe(rev.manifest())//- 生成一個rev-manifest.json
        .pipe(gulp.dest('rev/img'));
});

gulp.task("cleanJs",function(){
    return gulp.src(['dist/js/*','!dist/js/lib'],{read:false})
    .pipe(clean());
})

gulp.task('jsmin', ['cleanJs'], function () {
    gulp.src(['src/js/**/*.js','!src/js/**/*.min.js'])
        .pipe(jshint())
        .pipe(uglify())
        .pipe(rev({merge:true}))
        .pipe(gulp.dest('dist/js'))
        .pipe(rev.manifest())//- 生成一個rev-manifest.json
        .pipe(gulp.dest('rev/js'));
        
    gulp.src(['src/js/lib/**/*.js'])
        .pipe(gulp.dest('dist/js/lib'))
});

gulp.task('htmlmin',function () {
    var options = {
        removeComments: true,//清除HTML註釋
        //collapseWhitespace: true,//壓縮HTML
        removeEmptyAttributes: true,//刪除全部空格做屬性值 <input id="" /> ==> <input />
        minifyJS: true,//壓縮頁面JS
        minifyCSS: true//壓縮頁面CSS
    };
    gulp.src('src/html/**/*.html')
        .pipe(htmlmin(options))
        .pipe(rev())
        .pipe(gulp.dest('dist/html'))
        .pipe(rev.manifest())//- 生成一個rev-manifest.json
        .pipe(gulp.dest('rev/html'));
});


gulp.task('replaceURL', function(){
    gulp.src(['dist/html/**/*.html'])
        .pipe(replace('../css', '/css'))
        .pipe(replace('../js', '/js'))
        .pipe(replace('/src', '/dist'))
        .pipe(gulp.dest('dist/html'));
        
    gulp.src(['dist/css/**/*.css'])
        .pipe(replace('../css', '/css'))
        .pipe(replace('../js', '/js'))
        .pipe(replace('/src', '/dist'))
        .pipe(gulp.dest('dist/css'));
        
    gulp.src(['dist/js/**/*.js'])
        .pipe(replace('../css', '/css'))
        .pipe(replace('../js', '/js'))
        .pipe(replace('/src', '/dist'))
        .pipe(gulp.dest('dist/js'));
    
});

gulp.task('revUrl', function() {
    gulp.src(['rev/{css,img,js}/*.json', 'dist/html/**/*.html'])        //- 讀取 rev-manifest.json 文件以及須要進行css名替換的文件
    .pipe(revCollector())                               //- 執行文件內css名的替換
    .pipe(gulp.dest('dist/html'));    //- 替換後的文件輸出的目錄
    
    gulp.src(['rev/{css,img,js}/*.json', 'dist/css/**/*.css'])        //- 讀取 rev-manifest.json 文件以及須要進行css名替換的文件
    .pipe(revCollector())                               //- 執行文件內css名的替換
    .pipe(gulp.dest('dist/css'));    //- 替換後的文件輸出的目錄
    
    gulp.src(['rev/{css,img,js}/*.json', 'dist/js/**/*.js'])        //- 讀取 rev-manifest.json 文件以及須要進行css名替換的文件
    .pipe(revCollector())                               //- 執行文件內css名的替換
    .pipe(gulp.dest('dist/js'));    //- 替換後的文件輸出的目錄
    
});

gulp.task("autowatch",function(){
    gulp.watch(['src/sass/**/*.scss'],['sass']);        //監聽sacc文件改變後,編譯、去緩存
});


/*
 *    單步步驟:
 *     1.gulp sass                    編譯scss文件
 *     2.gulp jsmin                壓縮js
 *     3.gulp imgmin                壓縮圖片
 *     4.gulp htmlmin                壓縮HTML文件
 *     5.gulp replaceURL            替換相對路徑爲絕對路徑
 *     6.gulp revUrl                引用manifest給HTML添加版本號
 *     
 * 
 *     gulp sass jsmin htmlmin imgmin replaceURL revUrl
 * 
 * 
 * 
 * 若是改了scss文件:則執行:gulp sass
 * 若是改了js文件:則執行:gulp jsmin
 * 若是改了img文件:則執行:gulp imgmin
 * 
 * 只要改了HTML引用到的資源文件,最後都須要執行gulp htmlmin,gulp replaceURL,gulp revUrl,以清理緩存
 * */
View Code

根據最後的單步步驟,咱們來一步步解剖說明:npm

var gulp = require('gulp'),
    sass = require('gulp-sass'),                        //編譯sass
    cssmin = require('gulp-clean-css'),                    //壓縮css
    autoprefixer = require('gulp-autoprefixer'),        //添加瀏覽器前綴
    rev = require('gulp-rev'),                            //添加版本號
    revCollector = require('gulp-rev-collector'),        //添加版本號
    clean = require('gulp-clean'),                        //清理文目標文件夾
    csso = require('gulp-csso'),                        //合併css屬性
    csslint = require('gulp-csslint'),                    //css語法檢查
    csscomb = require('gulp-csscomb'),                    //css 樣式表的各屬性的順序
    imagemin = require('gulp-imagemin'),                //圖片壓縮
    cache = require('gulp-cache'),                        //緩存處理
    htmlmin = require('gulp-htmlmin'),                    //壓縮html
    replace = require('gulp-replace'),                    //替換路徑
    uglify = require('gulp-uglify'),                    //壓縮js
    jshint = require('gulp-jshint')                        //js語法檢查
;

這些都是執行任務時要用到的插件,看註釋大概就知道是幹嗎的了。json

 

 2.一、css相關處理:運行「gulp sass」

gulp.task("cleanCss",function(){
    return gulp.src('dist/css',{read:false})
    .pipe(clean());
});

gulp.task('sass', ['cleanCss'],function () {            //執行完cleanCss任務後再執行sass任務
      gulp.src('src/sass/**/*.scss')
    .pipe(sass())
    .pipe(cssmin())
    .pipe(autoprefixer())
    //.pipe(csscomb())
    .pipe(csso())
    .pipe(csslint())
    .pipe(rev())
    .pipe(gulp.dest('dist/css'))
    .pipe(rev.manifest())//- 生成一個rev-manifest.json
    .pipe(gulp.dest('rev/css'));
    
});

gulp.task("autowatch",function(){
  gulp.watch(['src/sass/**/*.scss'],['sass']); //監聽sacc文件改變後,編譯、去緩存
});

由於公司項目用的是sass,因此加了一個監放任務,去編譯生成css文件,css發生更改以後先執行「cleanCss」任務,清空dist文件夾下的css文件,重點是後面的.pipe(rev.manifest()),這一步將生成一個資源文件路徑的rev-manifest.json文件,裏面的內容是這樣的:

{
  "base/base.css": "base/base-c1e638e1f6.css",
  "controller/index.css": "controller/index-1454781768.css"
}

沒錯,這是用來最後在HTML文件替換css引用路徑的。

同時,dist/css目錄下也生成對應的文件:

 

2.二、img相關處理:運行「gulp imgmin」

gulp.task("cleanImg",function(){
    return gulp.src('dist/img',{read:false})
    .pipe(clean());
});

gulp.task('imgmin',['cleanImg'], function () {
    gulp.src('src/img/**/*.{png,jpg,gif,ico}')
        .pipe(cache(imagemin()))                        //沒有修改的圖片直接從緩存文件讀取
        .pipe(rev())
        .pipe(gulp.dest('dist/img'))
        .pipe(rev.manifest())//- 生成一個rev-manifest.json
        .pipe(gulp.dest('rev/img'));
});

過程就很少說啦,同樣的先清空dist的圖片文件夾,壓縮圖片,生成rev-manifest.json,生成的文件以下:

{
  "push-bg.jpg": "push-bg-6179117417.jpg"
}

   

 

2.三、js相關處理:運行「gulp jsmin」

gulp.task('jsmin', ['cleanJs'], function () {
    gulp.src(['src/js/**/*.js','!src/js/**/*.min.js'])
        .pipe(jshint())
        .pipe(uglify())
        .pipe(rev({merge:true}))
        .pipe(gulp.dest('dist/js'))
        .pipe(rev.manifest())//- 生成一個rev-manifest.json
        .pipe(gulp.dest('rev/js'));
        
    gulp.src(['src/js/lib/**/*.js'])
        .pipe(gulp.dest('dist/js/lib'))
});

過程就是檢查語法,壓縮,生成rev-manifest.json,要注意的地方是min類型的文件是放在lib目錄下,是不須要壓縮處理的,直接拷貝過去便可。生成的rev-manifest.json文件以下:

{
  "base/cal.js": "base/cal-2e41f44581.js",
  "base/require-config.js": "base/require-config-3c5aeda076.js",
  "controller/index.js": "controller/index-d14ed3eca8.js"
}

 

 

 2.四、js相關處理:運行「gulp htmlmin」

gulp.task('htmlmin',function () {
    var options = {
        removeComments: true,//清除HTML註釋
        //collapseWhitespace: true,//壓縮HTML
        removeEmptyAttributes: true,//刪除全部空格做屬性值 <input id="" /> ==> <input />
        minifyJS: true,//壓縮頁面JS
        minifyCSS: true//壓縮頁面CSS
    };
    gulp.src('src/html/**/*.html')
        .pipe(htmlmin(options))
        .pipe(rev())
        .pipe(gulp.dest('dist/html'))
});

過程省略一百字。。。

 

 2.五、替換相對路徑:運行「gulp replaceURL」

gulp.task('replaceURL', function(){
    gulp.src(['dist/html/**/*.html'])
        .pipe(replace('../css', '/css'))
        .pipe(replace('../js', '/js'))
        .pipe(replace('/src', '/dist'))
        .pipe(gulp.dest('dist/html'));
        
    gulp.src(['dist/css/**/*.css'])
        .pipe(replace('../css', '/css'))
        .pipe(replace('../js', '/js'))
        .pipe(replace('/src', '/dist'))
        .pipe(gulp.dest('dist/css'));
        
    gulp.src(['dist/js/**/*.js'])
        .pipe(replace('../css', '/css'))
        .pipe(replace('../js', '/js'))
        .pipe(replace('/src', '/dist'))
        .pipe(gulp.dest('dist/js'));
    
});

過程就是替換全部文件的相對路徑爲絕對路徑。

 

2.六、替換資源文件引用(重中之重):運行「gulp revUrl」

gulp.task('revUrl', function() {
    gulp.src(['rev/{css,img,js}/*.json', 'dist/html/**/*.html'])        //- 讀取 rev-manifest.json 文件以及須要進行css名替換的文件
    .pipe(revCollector())                                               //- 執行文件內css名的替換
    .pipe(gulp.dest('dist/html'));                                        //- 替換後的文件輸出的目錄
    
    gulp.src(['rev/{css,img,js}/*.json', 'dist/css/**/*.css'])        
    .pipe(revCollector())                               
    .pipe(gulp.dest('dist/css'));    
    
    gulp.src(['rev/{css,img,js}/*.json', 'dist/js/**/*.js'])        
    .pipe(revCollector())                               
    .pipe(gulp.dest('dist/js'));    
    
});

 

三、測試結果:

打開dist/html/index.html

<!doctype html>
<html>
    <head>
        <title>requirejs</title>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="/css/base/base-c1e638e1f6.css">
        <link rel="stylesheet" type="text/css" href="/css/controller/index-1454781768.css">
        <!--[if IE]>
            <link rel="stylesheet" type="text/css" href="/csstest/main.css"/>
        <![endif]-->
    </head>
    <body>
        <div class="main border-grey" id="name1">
            <div class="wrapper">未加載 index.js</div>
        </div>
        
        
        <script type="text/javascript" src="/js/base/require-config-3c5aeda076.js" defer="true"></script>
        <script data-main="/js/controller/index-d14ed3eca8.js" src="/js/lib/require.min.js" defer="true"></script>
    </body>
</html>

能夠看到,css和js文件引用的路徑都替換成了相應rev-manifest.json中的值。

 

訪問一下頁面:

控制檯也顯示資源文件引用正常:

3.一、修改測試

修改base.scss中body{font-size: 14px;}的字體爲20px,從新執行gulp,再截圖看下控制檯:

能夠發現,除了base.css引用變了以外,其餘保持不變。

 

四、補充:

按上面的步驟走完,gulp已經知足項目基本須要了,但仍存在兩點問題:

  1. 對經過require-config.js引入的js文件修改後,沒有更新到
  2. 每次gulp運行完後都會生成新的文件,開發環境是作了清除dist目錄處理,但對於通常公司服務器而言,發佈到生產環境上,不可能每次發佈都對dist作清空處理,文件只會越積越多
  3. 咦,怎麼跟前言博客園截圖引用的方法不同。。。

上面這3點,將在下一節中詳解。

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

歡迎轉載,轉載請註明做者:飄飛的夏秋 和出處 http://www.cnblogs.com/chenchenghua/p/5953767.html

相關文章
相關標籤/搜索