在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建
剛開始打算進行前后端分離開發,后來發現在使用JSP或者Freemarker做動態頁面時,想發揮這些自動化構建工具牛逼閃閃的livereload功能并不是那么的輕易,因為我們必須還得調教它們去調用Java容器。現在全球社區似乎還沒有成熟的插件可以自動幫我們調教Java容器,百度Fis的Jello也只是做了一下velocity的自動化,自己寫感覺就是自虐,所以在這個問題上倒不如把Gulp當成一個Maven來使用,反正J2EE開發人員應該大都習慣了修改代碼之后漫長無盡的build。相反,如果對Gulp調教好了watchify,只對發生了修改的文件進行重新構建,那么速度必定不是問題,也不必要我們每次修改都手動打包。
目前剛剛開始應用這一技術,用Gulp主要為了做前端工程和代碼優化,之所以沒有選擇相較而言社區更加健壯的Grunt,可能主要還是因為Gulp的代碼寫起來更加輕松,而且采用Stream對構建速度有明顯的提升。本文使用Gulp主要為了實現以下幾個功能:優化CSS,對CSS進行合并,壓縮,加MD5版本控制,生成Map映射;優化JS,對JS進行合并,壓縮,加MD5版本控制,生成Map映射;優化JSP頁面文件,自動產生對應原始文件壓縮后資源文件的路徑。我們最終要達到的效果是,壓縮后的CSS文件一個,壓縮后的JS文件一個,JSP頁面自動產生對應MD5版本的資源文件。之所以要加MD5進行文件版本控制,是因為MD5在文件未發生修改的情況下,是不會發生改變的,因此服務器相應的資源就不需要進行替換。我們還要考慮到將所有同類資源合并到一個文件內的弊端,那就是如果網站內容較多時,可能大部分資源并不是一個頁面真正需要的,這并不是理想的優化效果。對于這個問題,我們可以考慮結合使用browserify等模塊管理工具。更省事的方法是,簡單分析一下網站對資源的需求。一般的站點通常有一個門戶網站和一個后臺管理系統,門戶網站頁面使用到的資源和后臺管理系統使用的資源可能會有較大的差異性,而兩者自身的頁面之間其實差異并不是非常大。所以我們也可以專門為門戶網站和后臺系統設計兩套資源,省去了使用Browserify構建可能產生的大量冗余文件。
使用Gulp之前,我們首先需要安裝一下Node.js和NPM包管理工具。因為我們是在Maven+Spring框架下做前端開發,因此在正式寫代碼之前,還需要搭建好一個maven的項目。一個典型的Maven項目可以如下圖所示,在這里我們加了2個maven項目模塊,靜態資源放在webapp模塊中,動態頁面放在WEB-INF內,配置完成之后,maven項目就可以正常工作了。
?類似于maven,npm和gulp也需要相應的配置文件,分別是package.json和gulpfile.js。gulp中我們所需要用到的插件如下:
<!-- lang: js --> var gulp = require('gulp'), rev = require('gulp-rev'), minifycss = require('gulp-minify-css'), uglify = require('gulp-uglify'), concat = require('gulp-concat'), sourcemaps = require('gulp-sourcemaps'), del = require('del'), revreplace = require('gulp-rev-replace');使用npm install package-name --save-dev指令可以進行對應插件的安裝,或者在配置好package.json文件之后,使用npm install進行一次性安裝,所有這些庫文件會生成到根目錄下的node_module文件夾內。
gulp的工作流程如下:
首先在項目根目錄下創建一個src文件夾,將前端需要的靜態資源放在文件夾內作為源碼開發使用。gulp工作流首先讀取這些文件,進行對應的合并壓縮處理,最后將產品輸出到maven模塊相應的靜態資源路徑和動態頁面路徑下,這樣就完成了一整套簡單的自動化構建過程。在下面這個例子中,我們分別構建一個簡單的登陸頁面和后臺頁面流程,最后用一個gulp默認指令完成全部工作。首先定義一下文件輸入目錄:
<!-- lang: js --> var path = {css: 'maven-webapp/webapp/static/css',js: 'maven-webapp/webapp/static/js',jsp: 'maven-webapp/webapp/WEB-INF/jsp' };然后寫一個login界面的css壓縮合并優化生產線。如下文所示,在這段代碼中,我們首先用"del"指令刪除上一次構建產生的舊文件。其中rev-manifest.json是MD5版本工具輸出的一組數據,它的作用是記錄合并后的文件添加了MD5版本數之后的文件名。將4個文件進行合并,合并之前初始化sourcemap,這樣在處理完成之后可以生成映射文件,有了這個映射文件,我們就可以在谷歌瀏覽器的調試工具下面查看到壓縮前源碼的形式。concat執行文件合并指令,path定義了合并結果的文件名,合并之后用minifycss壓縮整理,緊接著給文件加上MD5版本號,到這里修改完成,寫出映射文件,并將結果導出到maven項目的目錄里面。
<!-- lang: js --> gulp.task('login-css-min', function() { del(['rev-manifest.json',path.css + '/login.*.*',path.js + '/login-bundle.*.*',path.jsp + '/login.jsp'], function(err, deletedFiles) {console.log('Files deleted:\n', deletedFiles.join('\n')); }); return gulp.src(['src/css/bootstrap.css','src/css/bootstrap-reset.css','src/css/style-responsive.css','src/css/login.css']).pipe(sourcemaps.init()).pipe(concat({path:'login.min.css', cwd: ''})).pipe(minifycss()).pipe(rev()).pipe(sourcemaps.write('.')).pipe(gulp.dest(path.css)).pipe(rev.manifest()).pipe(gulp.dest('')); });js的合并和壓縮是類似的。但是需要注意,當我們合并js的時候,還是盡量使用閉包的匿名函數,避免插件污染全局變量。在下面的代碼中,我在最頭上加了一個namespace.js的文件,將它暴露在全局環境中,目的就是讓它做命名空間的管理。
<!-- lang: js --> gulp.task('login-js-min', ['login-css-min'], function() { return gulp.src(['src/js/Namespace.js', 'src/js/lib/jquery.js', 'src/js/main.js']).pipe(sourcemaps.init()).pipe(concat({path:'login-bundle.min.js', cwd: ''})).pipe(uglify()).pipe(rev()).pipe(sourcemaps.write('.')).pipe(gulp.dest(path.js)).pipe(rev.manifest({base:'', merge: true})).pipe(gulp.dest('')); });第三步,根據rev-manifest.json的文件名映射,把jsp內對應的資源路徑修改成加了MD5版本數字后的路徑名。
<!-- lang: js --> gulp.task("login-build", ['login-js-min'], function() { var manifest = gulp.src("rev-manifest.json"); return gulp.src( "src/jsp/login.jsp").pipe(revreplace({replaceInExtensions: ['.jsp'], manifest: manifest})).pipe(gulp.dest(path.jsp)); });同樣的方法做一下后臺頁面的資源合并壓縮:
<!-- lang: js --> gulp.task('index-css-min', function() { del(['rev-manifest.json',path.css + '/index.*.*',path.js + '/index-bundle.*.*',path.jsp + '/index/*.*'], function(err, deletedFiles) {console.log('Files deleted:\n', deletedFiles.join('\n')); }); return gulp.src(['src/css/index/jquery.fullPage.css','src/css/index/tipso.min.css','src/css/index/show.css','src/css/index/style.css']).pipe(sourcemaps.init()).pipe(concat({path:'index.min.css', cwd: ''})).pipe(minifycss()).pipe(rev()).pipe(sourcemaps.write('.')).pipe(gulp.dest(path.css)).pipe(rev.manifest()).pipe(gulp.dest('')); });gulp.task('index-js-min', ['index-css-min'], function() { return gulp.src(['src/js/Namespace.js','src/js/lib/jquery.js','src/js/lib/jquery.*.min.js','src/js/lib/jquery-ui-1.10.3.min.js','src/js/lib/smooth-scroll.min.js','src/js/lib/tipso.min.js','src/js/lib/transit.js','src/js/index/*.js']).pipe(sourcemaps.init()).pipe(concat({path:'index-bundle.min.js', cwd: ''})).pipe(uglify()).pipe(rev()).pipe(sourcemaps.write('.')).pipe(gulp.dest(path.js)).pipe(rev.manifest({base:'', merge: true})).pipe(gulp.dest('')); });gulp.task("index-build", ['index-css-min','index-js-min'], function() { var manifest = gulp.src("rev-manifest.json"); return gulp.src( "src/jsp/index/*.jsp").pipe(revreplace({replaceInExtensions: ['.jsp'], manifest: manifest})).pipe(gulp.dest(path.jsp + '/index/')); });最后將兩個步驟合并到default中去,就完成了自動化。
<!-- lang: js --> gulp.task('default', ['login-build', 'index-build'], function() { // place code for your default task here });結果如下圖所示:
如果需要讓多個jsp頁面共用一塊資源,可以將這些頁面放在一個文件夾中統一進行處理。
總結
以上是生活随笔為你收集整理的在Maven+Spring项目中使用Node.js的Gulp进行前端自动化构建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: const 应用
- 下一篇: strcat()的实现