前端基于gulp后端基于freemarker的工作流程总结
前言
最近在做一個PC端的項目,由于項目需要兼容到IE8,所以從技術選型上采取了公司之前一直沿用的前端基于gulp后端基于freemarker的模式來進行開發。
那么gulp+freemarker這種開發模式的流程到底是怎樣的呢?我這邊就來簡單的分析一下。
一、前端基于gulp
前端技術棧:
- gulp
- jquery
- ajax
- less...
前端項目結構:
├── README.md 項目介紹 ├── src 源碼目錄 │ ├── common ├── less 公共樣式├── js 公共js├── plugins 插件 項目公共文件 │ ├── img 圖片 │ ├── js js │ ├── less 樣式 ├── .eslintrc.js eslint規則配置 ├── package.json 工程文件 ├── gulpfile.js 配置文件 ├── server.js 本地服務 復制代碼從目錄來看,非常簡單,我這邊就主要來分析一下gulpfile.js和server.js
gulpfile.js
熟悉gulp的同學都知道,一般我們會將整個項目兩種環境來調用,即開發環境和生產環境
開發環境的配置:
var gulp = require("gulp"),less = require("gulp-less"),clean = require("gulp-clean"),header = require("gulp-header");/*** less 編譯* @return {[type]} [description]* 開發環境調用*/ gulp.task("less", ["cleanCss"], function() {gulp.src(['src/less/*.less','src/common/less/*.less']).pipe(plumber({errorHandler: errorHandler})).pipe(less()).pipe(addHeader()).pipe(gulp.dest('dist/css'));});/*** js 編譯* @return {[type]} [description]* 開發環境調用*/ gulp.task('js', ['cleanJs'], function() {gulp.src(['src/js/*.js', 'src/common/js/*.js']).pipe(plumber({errorHandler: errorHandler})).pipe(addHeader()).pipe(gulp.dest('dist/js'));gulp.src('src/common/plugins/*.js').pipe(gulp.dest("dist/js/plugins")) })/*** img 輸出* @return {[type]} [description]* 開發環境調用*/ gulp.task("imgOutput", ["cleanImg"], function(){gulp.src('src/img/**/*.*').pipe(gulp.dest("dist/img"))}) 復制代碼簡析上述代碼:
在開發環境中我們需要對我們項目的src下的業務less、js、img和common下的公共less、js、img進行編譯打包,那么我們就需要借助gulp.task()這個方法來建立一個編譯任務。創建完任務以后,我們就需要通過gulp.src()來指向我們需要編譯的文件
最后我們再通過gulp.pipe()來創建一個又一個我們需要的管道,如
gulp.pipe(plumber({errorHandler: errorHandler}))
function errorHandler(e) {// 控制臺發聲,錯誤時beep一下gutil.beep();gutil.log(e); } 復制代碼編譯的時候控制臺打印錯誤信息。
gulp.pipe(addHeader())
/*** 在文件頭部添加時間戳等信息*/ var addHeader = function() {return header(banner, {pkg: config,moment: moment}); };復制代碼編譯以后在文件的頭部加上編譯時間
gulp.pipe(gulp.dest('dist/js'))
將編譯后的文件輸出到dist目錄下
生產環境的配置:
var gulp = require("gulp"),less = require("gulp-cssmin"),clean = require("gulp-uglify");header = require("gulp-header")/*** css build* @return {[type]} [description]* 正式環境調用*/ gulp.task("cssmin", ["cleanCss"], function() {gulp.src('src/common/less/all.base.less').pipe(less()).pipe(cssmin()).pipe(rename({suffix: '.min'})).pipe(addHeader()).pipe(gulp.dest("dist/css"));gulp.src('src/less/*.less').pipe(less()).pipe(cssmin()).pipe(addHeader()).pipe(gulp.dest("dist/css"));});/*** js 編譯* @return {[type]} [description]* 正式環境調用*/ gulp.task('jsmin', ['cleanJs'], function() {gulp.src(['src/js/**/*.js', 'src/common/js/**/*.js']).pipe(plumber({errorHandler: errorHandler})).pipe(uglify()).pipe(addHeader()).pipe(gulp.dest('dist/js'));gulp.src('src/common/plugins/**/*.js').pipe(uglify({mangle: true})).pipe(addHeader()).pipe(gulp.dest("dist/js/plugins")) }) 復制代碼關于生產環境的配置其實跟上述的開發環境配置原理差不多,區別將在于生產環境中我們需要借助gulp-cssmin和gulp-uglify將css和js都進行壓縮,縮小文件的體積。
這里提一下cleancss和cleanjs的意思,其實就是在我們每一次編譯打包的時候將原來已經打包生成css和js都清理調,這樣保證我們每次編譯打包的代碼都是最新的。
gulp.task("cleanCss", function() {return gulp.src('dist/css', {read: false}).pipe(clean()); });gulp.task("cleanJs", function() {return gulp.src('dist/js', {read: false}).pipe(clean()); });gulp.task("cleanImg", function() {return gulp.src('dist/img', {read: false}).pipe(clean()); }); 復制代碼開發環境監聽
gulp.task("watch", function() {livereload.listen();// 調用gulp-watch插件實現編譯有改動的LESS文件gulp.watch(['src/less/*.less','src/common/less/*.less'], function(file) {gulp.src(file.path).pipe(plumber({errorHandler: errorHandler})).pipe(less()).pipe(addHeader()).pipe(gulp.dest('dist/css'));});gulp.watch(['src/js/**/*.js', 'src/common/js/**/*.js'], function(file) {gulp.src(file.path).pipe(gulp.dest("dist/js"))});// 監聽圖片改動gulp.watch('src/img/**/*.*', function(file){gulp.src(file.path).pipe(gulp.dest("dist/img"))})// 監聽有變化的css,js,ftl文件,自動刷新頁面gulp.watch(['dist/**/*.css', 'dist/**/*.js', ftlPath]).on('change', livereload.changed);}); 復制代碼在開發項目的時候我們需要借助gulp.watch()來實時的監聽項目中代碼的改動,并且通過gulp-livereload這個插件來實時的刷新我們的頁面,以提高我們的開發效率。
說完gulpfile.js后我們再來分析一下server.js
server.js
const path = require('path'),express = require('express'),proxy = require("express-http-proxy"),compress = require('compression'),app = express(),fs = require('fs'),config = require('./package.json'),projectName = config.name,port = process.env.PORT || '9091'// GZIP壓縮 app.use(compress());// 設置響應頭 app.use(function(req, res, next) {res.header('X-Powered-By', 'Express');res.header('Access-Control-Allow-Origin', '*');next(); })// 當前靜態項目的資源訪問 app.use('/' + projectName, express.static('dist')); app.use('/html', express.static('src/pages'));// 靜態服務器監聽 app.listen(port, '0.0.0.0', function() {console.log('static server running at ' + port) }) 復制代碼這里我們通過node中express框架來為我們搭建本地服務,這里重點提一下靜態資源項目的訪問
通過app.use()方法傳入兩個參數,其中projectName代表的是我們在package.json中定義項目名稱,如下phip_ehr
{"name": "phip_ehr","version": "1.0.0","description": "","main": "index.js","scripts": {"start": "gulp && gulp watch","build": "NODE_ENV=production gulp build","server": "node server.js"} 復制代碼第二個參數express.static('dist')意思是將我們的服務代理到編譯打包后的dist文件下如:http://192.168.128.68:9091/phip_ehr/js/**.js
這樣以來我們將可以輕松的獲取到整個項目下的所有靜態了。
二、后端基于freemarker
后端端技術棧:
- java
- freemarker ...
這里后端的項目結構我這邊只截取跟我們前端相關的目錄來說明
后端端項目結構:
├── templates 項目模版 │ ├── home ├── layouts 頁面布局├── views 業務代碼(ftl)├── widgets 項目依賴復制代碼layouts
default.ftl
<!DOCTYPE HTML> <html><head><link rel="dns-prefetch" href="${staticServer}"><meta http-equiv="X-UA-Compatible" content="IE=edge">${widget("headInner",page.bodyAttributes)}<#list page.styles as style><#if (style?index_of('http') > -1) ><link href="${style}?v=${version}" rel="stylesheet" type="text/css" /><#else><link href="${staticServer}/phip_ehr/css/${style}?v=${version}" rel="stylesheet" type="text/css" /></#if></#list></head><body>${widget("header",page.bodyAttributes)}<div id='gc'>${placeholder}</div>${widget("footerJs")}</body> </html> 復制代碼上述代碼是整個項目頁面的布局結構
${widget("headInner",page.bodyAttributes)}
這個方法意思是引入一些我們前端靜態的公共樣式和一些公共的meta標簽。
headInner.ftl
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta property="wb:webmaster" content="3b0138a4c935e0f6" /> <meta property="qc:admins" content="341606771467510176375" /> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /><link rel="stylesheet" href="${staticServer}/phip_ehr/css/reset.css?v=${version}" type="text/css"/> <link rel="stylesheet" href="${staticServer}/phip_ehr/css/common.css?v=${version}" type="text/css"/> 復制代碼這里提一下${staticServer}這個當然指的就是我們靜態域名了,需要在后端項目的配置文件config中來聲明,即指向我們前端的靜態服務
**.mursi.attributesMap.staticServer=http://192.168.128.68:9091 **.mursi.attributesMap.imgServer=http://192.168.128.68:9091 復制代碼引入完我們的公共樣式以后,那接下來我們業務樣式怎么引入呢?
<#list page.styles as style><#if (style?index_of('http') > -1) ><link href="${style}?v=${version}" rel="stylesheet" type="text/css" /><#else><link href="${staticServer}/phip_ehr/css/${style}?v=${version}" rel="stylesheet" type="text/css" /></#if> </#list> 復制代碼這段代碼就是用來引入我們的業務樣式的,意思是利用后端框架封裝的page這個對象中style屬性,然后對所有頁面的style標簽進行遍歷
然后在我們業務代碼(ftl)中將可以通過addstyle這個方法來引入我們的業務樣式了
${page.addStyle("audit.css")} 復制代碼${widget("header",page.bodyAttributes)}
這個方法的意思是引入我們頁面中公共的頭部
${placeholder}
這個意思是引入我們頁面主體內容部分
${widget("footerJs")}
這個意思是引入我們頁面中js文件
footerJS.ftl
<script type="text/javascript">$GC = {debug: ${isDev!"false"},isLogined : ${isLogin!"false"},staticServer : '${staticServer}',imageServer : '${imageServer}',kanoServer : '${kanoServer}',version:"${version}",jspath:"${staticServer}" + "/phip_ehr/js"};// $GS { Array } - the init parameters for startup$GS = [$GC.jspath + "/plugins/jquery-1.8.1.min.js",$GC.jspath + "/GH.js?_=${version}",$GC.jspath + '/plugins/validator.js',function(){// load common moduleGL.load([GH.adaptModule("common")]);// load the modules defined in pagevar moduleName = $("#g-cfg").data("module");if(moduleName){var module = GH.modules[moduleName];if(!module) {module = GH.adaptModule(moduleName);}if(module) {GL.load([module]);}}}]; </script><!-- 引入js模塊加載器 --> <script type="text/javascript" src="${staticServer}/phip_ehr/js/GL.js?_=${version}" ></script><script src="http://127.0.0.1:35729/livereload.js"></script>復制代碼這段代碼中$GC就指的是初始化一些變量,然后$GS中就是引入我們項目中依賴的公共js,如jquery、common.js等。其次是通過GL.js這個模塊加載器來加載我們的業務js
這樣我們就可以在我們的業務ftl中通過data-moduls來引入每個頁面中的業務js了
a.ftl
<div class="g-container gp-user-info J_UserInfo" id="g-cfg" data-module="a" data-fo-appcode="1" data-header-fixed="1" data-page="infirmary"></div> 復制代碼a.js
GH.run(function() {GH.dispatcher('.J_Home', function() {return {init: function() {this.switchPatient();},/*** * 切換就診人檔案*/switchPatient: function() {console.log(1);}}}) }, [GH.modules['validator'],GH.modules['datepicker']]); 復制代碼dispatcher就是相當于頁面的分發器,當然每個頁面只能擁有一個獨立的分發器,run()方法就是我們封裝在GH.js的公共調用方法
那么我們項目中引入 一些公用的插件要怎么引入呢?
那么我們就在GH.js里封裝了GH.modules()方法來引入插件,這里就不詳細的說明了。
這里順帶也提一下ftl,什么是ftl?ftl就是類似于我們的html一樣,但是它不同的地方就是它是基于freemarker語法來進行編寫的一種后端模版引擎。我們項目中一些可以同步加載的數據都可以利用freemarker的語法在ftl中直接進行操作
小結:
這種前后端不分離的模式有哪些優缺點呢?
優點:雖然在開發效率上比不上純前后端分離的模式(vue+webpack,react+webpack),但是針對一些對于兼容性要求很高的多頁項目,這種開發模式也是可取的。
缺點:對后端服務依賴太強,往往后端服務一旦出現報錯或者掛掉后,前端的工作就沒有辦法開展下去了,從而加大了前后端的開發成本。
總結
以上是生活随笔為你收集整理的前端基于gulp后端基于freemarker的工作流程总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小K的农场(luogu P1993
- 下一篇: pycharm 基本设置