前言
前端圈里,現(xiàn)在工程化的前端已經(jīng)是主流.各種前端工程化的技術(shù)比比皆是.webpack.grunt ,gulp等等等,應(yīng)接不暇.
而再回看jsp當(dāng)前的環(huán)境.當(dāng)真的落后了前端圈太多.整體的開(kāi)發(fā)模式,還是很多年前傳統(tǒng)的企業(yè)級(jí)web開(kāi)發(fā)模式.大把的jsp標(biāo)簽.struts標(biāo)簽去實(shí)現(xiàn)頁(yè)面.也無(wú)怪乎只能做傳統(tǒng)企業(yè)后臺(tái)網(wǎng)址.
我之前工作的杭州某公司就是如此,用jsp標(biāo)簽包裝了extjs的組件. 所有的html代碼都寫在java代碼里.通過(guò)xml配置來(lái)構(gòu)造頁(yè)面.確實(shí)很大的提升了開(kāi)發(fā)效率(所有的開(kāi)發(fā)都在配xml和寫一些基本的邏輯).但是蛋疼的就是,寫完頁(yè)面后,整體風(fēng)格丑陋.客戶總是會(huì)讓你修改頁(yè)面.這個(gè)時(shí)候你固化的組件反而會(huì)成為你的硬傷,可能修改頁(yè)面一點(diǎn)點(diǎn)布局和風(fēng)格.就要大把的改java代碼.
后面擺脫了這樣的公司,我開(kāi)始嘗試更主流的一下web開(kāi)發(fā)方式.放棄丑陋的ext,經(jīng)歷了純jquery時(shí)代,逐漸過(guò)渡到當(dāng)前的angular/vue 的MVVM前端框架.更快的開(kāi)發(fā)效率.和更大氣美觀的頁(yè)面風(fēng)格.已經(jīng)成為我們這邊開(kāi)發(fā)的主要技術(shù)體系.后臺(tái)java實(shí)現(xiàn).弱化了后臺(tái)業(yè)務(wù).主要的交互頁(yè)面都放在了angular的控制層和service層來(lái)實(shí)現(xiàn).
當(dāng)技術(shù)體系逐漸完善后,效率問(wèn)題也隨之而來(lái).之前的傳統(tǒng)企業(yè)網(wǎng)站是沒(méi)有考慮過(guò)js,css壓縮,合并等等.現(xiàn)在考慮的時(shí)候,選擇一個(gè)工程化的前端工具就至關(guān)重要. 調(diào)研過(guò)webpack和百度的fis等技術(shù)后.我最終選擇了gulp.首先因?yàn)間ulp的流式編寫方式特別清晰.其次,我們的開(kāi)發(fā)工具全都是IntelliJ IDEA ,作為世界上最好用的java開(kāi)發(fā)idea.居然在界面上友好的支持gulp的任務(wù)執(zhí)行.支持界面的gulp task調(diào)試剛發(fā)現(xiàn)的時(shí)候我激動(dòng)哭了好嗎?
一.gulp入門
gulp是前端開(kāi)發(fā)過(guò)程中對(duì)代碼進(jìn)行構(gòu)建的工具留特,是自動(dòng)化項(xiàng)目的構(gòu)建利器;她不僅能對(duì)網(wǎng)站資源進(jìn)行優(yōu)化碎节,而且在開(kāi)發(fā)過(guò)程中很多重復(fù)的任務(wù)能夠使用正確的工具自動(dòng)完成蟹瘾;使用她,我們不僅可以很愉快的編寫代碼腹尖,而且大大提高我們的工作效率柳恐。
安裝和使用gulp.需要安裝node環(huán)境.并且使用node的npm管理工具. 如果沒(méi)有接觸過(guò)前端知識(shí).看見(jiàn)node和npm確實(shí)挺懵逼的. 其實(shí)不然,對(duì)于一個(gè)java老鳥(niǎo)來(lái)說(shuō).npm你就簡(jiǎn)單的理解成maven即可.其實(shí)是前端圈里形成的一個(gè)類maven的倉(cāng)庫(kù),npm提供各種node插件的下載.命令也很簡(jiǎn)單. npm init 就類似于mvn:eclipse 項(xiàng)目下會(huì)生成package.json文件,類似于pom.xml
請(qǐng)自學(xué)教程.
再自行安裝gulp.傳送門如下.
gulp詳細(xì)入門.node,npm和gulp安裝.
需要注意的是.npm安裝插件分為全局安裝和局部安裝.全局安裝指安裝好的組件會(huì)全部工程通用.而局部安裝只對(duì)當(dāng)前工程使用. 而gulp不但需要全局安裝,同時(shí)需要對(duì)當(dāng)前項(xiàng)目局部安裝.否則無(wú)法正常使用.
在根目錄添加一個(gè)gulpfile.js 即gulp的任務(wù)腳本文件.
在命令行輸入 gulp 任務(wù)名 即可執(zhí)行腳本里對(duì)應(yīng)任務(wù)名的任務(wù).
<pre>
以下是任務(wù)代碼范例
var gulp = require('gulp')
var concat = require('gulp-concat');//合并組件
var uglify=require('gulp-uglify');//壓縮組件
var clean = require('gulp-clean');//清空文件夾組件
var replace = require('gulp-replace');
var cheerio = require('gulp-cheerio');//dom操作組件
gulp.task('testConcat', function () {
gulp.src('dist/js')
.pipe(clean());
gulp.src('js/*.js')
.pipe(concat('all.min.js'))//合并后的文件名
.pipe(gulp.dest('dist/js'));
});
</pre>
二,日常應(yīng)用場(chǎng)景和gulp插件
從上面的代碼范例可以看到.gulp的任務(wù)在一開(kāi)始需要引入各式各樣的插件.其實(shí)gulp本身只是提供了一種對(duì)文件處理的平臺(tái).
讀入一個(gè)或者一批文件.調(diào)用不同的插件串式的對(duì)文件進(jìn)行一步步的處理.最終輸出到taregt目錄.
整體跟java的流處理沒(méi)什么大的區(qū)別.輸入文件.最后寫入等等.
<pre>
gulp.src('js/*.js') //讀取統(tǒng)配命令命中的所有文件
.pipe(concat('all.min.js'))//地阿偶concat插件對(duì)輸入流合并處理,方法的參數(shù)是合并后的新文件名
.pipe(gulp.dest('dist/js'));//把流輸出到dist/js目錄下
</pre>
日常最項(xiàng)目上其實(shí)用的場(chǎng)景大概是這樣的:
使用angular進(jìn)行開(kāi)發(fā),angular的service.js,controller.js,filter.js各是一個(gè)文件.文件都未曾壓縮.源文件jsp上有三個(gè)<script>引入文件.
而開(kāi)發(fā)結(jié)束后.基于網(wǎng)頁(yè)優(yōu)化要做的就是:
- 為了減少http請(qǐng)求,把三個(gè)js合并成一個(gè)js,
- 為了減少js請(qǐng)求的加載時(shí)間,把合并后的js壓縮成一個(gè)min.js
- 原來(lái)的三個(gè)js已經(jīng)變成了一個(gè)js.需要把輸出的jsp文件里的三個(gè)<script>去掉.換成引用新的min.js
所使用到的插件分別是
- gulp-concat 文件合并插件
- gulp-uglify 文件壓縮插件
-
gulp-cheerio dom操作修改dom插件
<pre>
源文件:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Hello, World</title>
<jsp:include page="/WEB-INF/jsp/include/jquery.jsp"></jsp:include>
<script src="js/angular.js"> </script>
<script src="js/service.js"> </script>
<script src="js/controller.js"> </script>
<script src="js/filter.js"> </script>
</head>
<body>
<%=aa%>
</html>
</pre>
<pre>
期望結(jié)果:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Hello, World</title>
<jsp:include page="/WEB-INF/jsp/include/jquery.jsp"></jsp:include>
<script src="js/all.min.js"></script></body>
</head>
<body>
<%=aa%>
</html>
</pre>
對(duì)此,我們修改gulpfile.js.寫上自己的合并壓縮替換任務(wù)代碼
<pre>
var gulp = require('gulp');
var concat = require('gulp-concat');//合并組件
var uglify=require('gulp-uglify');//壓縮組件
var cheerio = require('gulp-cheerio');//dom操作組件
gulp.task('testConcat', function () { // testConcat就是任務(wù)名 在命令行執(zhí)行g(shù)ulp testConcat即可執(zhí)行此任務(wù)
// 任務(wù)第一步,對(duì)js文件進(jìn)行處理
gulp.src('js/*.js') //加載所有的js
.pipe(concat('all.min.js'))//調(diào)用合并組件方法concat(),合并這些js.并起一個(gè)新的名稱
//任務(wù)第二步,對(duì)合并的文件進(jìn)行壓縮
.pipe(uglify()) //調(diào)用壓縮組件方法uglify()
.pipe(gulp.dest('dist/js')); //輸出到目標(biāo)目錄
//任務(wù)第三步,對(duì)jsp文件進(jìn)行處理.
gulp.src('index.jsp') //加載源jsp.
.pipe(cheerio(function ($) { //調(diào)用cheerio插件進(jìn)行dom操作
$('script').remove(); //cheerio類似于jquery dom操作. 通過(guò)jq操作移除原節(jié)點(diǎn),append新節(jié)點(diǎn)
$('head').append('<script src="js/all.min.js"></script>');
}))
.pipe(gulp.dest('dist'));
});
</pre>
命令行,或者idea運(yùn)行 gulp的任務(wù).即可得到結(jié)果
這里有一個(gè)坑.,能看到運(yùn)行結(jié)果并不是我們期望的完好的jsp. 頁(yè)面的jsp標(biāo)簽亂掉了.
這是因?yàn)閏heerio 插件他在做dom操作的時(shí)候,首先需要把源文件html進(jìn)行智能補(bǔ)全處理,會(huì)把未結(jié)束的標(biāo)簽補(bǔ)齊.他本身是操作html的.并不支持jsp的dom操作.
當(dāng)然,我們也有處理的辦法.稍微調(diào)整一下任務(wù)代碼.在調(diào)用cheerio 之前,先把jsp標(biāo)簽的<% 和%>替換掉. 這樣cheerio 會(huì)以為他們是普通的字符串.等cheerio 處理結(jié)束后,我們?cè)谔鎿Q回來(lái).
<pre>
gulp.task('testConcat2', function () {
gulp.src('js/*.js')
.pipe(concat('all.min.js'))//合并后的文件名
.pipe(uglify())
.pipe(gulp.dest('dist/js'));
gulp.src('index.jsp')
.pipe(replace("<%","~%")) //替換掉jsp標(biāo)簽的<%
.pipe(replace("%>","%~"))//替換掉jsp標(biāo)簽的<%
.pipe(cheerio(function ($) {
$('script').remove();
$('head').append('<script src="js/all.min.js"></script>');
}))
.pipe(replace("%~","%>")) //替換回來(lái)jsp標(biāo)簽的<%
.pipe(replace("~%","<%"))//替換回來(lái)jsp標(biāo)簽的<%
.pipe(gulp.dest('dist'));
});
</pre>
這樣,一個(gè)簡(jiǎn)單的jsp上場(chǎng)景就用gulp做了壓縮優(yōu)化處理了.最終結(jié)果
當(dāng)然gulp還有很多其他插件,比如壓縮html內(nèi)容.混淆壓縮js等等.按照情況選用