在传统java项目里面写jsp页面,起码有三大缺陷。
- 同一个页面由于代码存在冲突风险,很难多人开发。
- 页面之间的样式和组件很难复用,维护困难。
- 改完之后要刷新,不支持热更新。
后来我尝试使用gulp对页面文件进行代码拆分再合并,用browser-sync进行页面刷新,开发体验比原先好很多。
详细代码看git地址
开始的时候,我决定先把目录结构定下来。因为习惯了vue项目开发,我仿照了vue的目录结构。

事实上这不是真正意义上的组件,我只是把页面按照逻辑进行了划分,每个文件夹包含ejs,js,less 三种文件。每种文件可能不止一个,例如这个块涉及到的js文件,如果我想把它分成两个,也是可以的。到时使用gulp-concat 合并时,会按照文件名的顺序把代码合并到同一个文件中。
gulp.src(paths)
.pipe(concat({ path: fileName + '.js' }))
.pipe(gulp.dest(filePath))
.pipe(gulp.dest(javaPath))
.on("end", end);
less 文件需要先用gulp-less进行解析,生成的css再用gulp-concat进行合并。我这里还做了一些处理,用postcss 对代码前缀进行了添加。不过我并不想对最终结果进行压缩,也许后面的开发者需要对结果文件进行改动呢。
var concat = require('gulp-concat');//合并javascript
var postCss = require('gulp-postcss');
var autoprefixer = require('autoprefixer');
var plugins = [
autoprefixer({ overrideBrowserslist: ["> 1%", "last 2 versions", "not ie <=8"] })
]
gulp.src(paths)
.pipe(lessConvert())
.pipe(concat({ path: fileName + '.css' }))
.pipe(postCss(plugins))
.pipe(gulp.dest(filePath))
.pipe(gulp.dest(javaPath))
.on("end", end);
而ejs文件不存在合并的问题,它的模板语法有引入块的机制,例如
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<%-include("../../components/common/layout/prepend", {pageName: 'bigscreen'})%>
</head>
<body>
<div>hello bigscreen</div>
<%-include("../../components/common/header/dom", {})%>
<%-include("./left/dom", {})%>
<%-include("./right/dom", {})%>
<%-include("../../components/common/bottom/dom", {})%>
<%-include("../../components/common/layout/append", {pageName: 'bigscreen'})%>
</body>
</html>
解析是通过gulp-ejs对入口文件进行处理,最终会生成一个页面文件。
var ejsConvert = require('gulp-ejs');
// 此处只展示核心代码
gulp.src(prodPaths[0])
.pipe(ejsConvert({}))
.pipe(rename(p => {
p.basename = fileName
p.extname = '.jsp'
}))
.pipe(gulp.dest(javaPath))
.on("end", end);
大概的方案确定下来。到了关键的一步,我们需要对目录路径进行解析,才能得到我们想要的结果。最终确定的配置类似这样:
pages数组中,一个item定义一个页面,因此你可以定义多个页面,让他们共用一些组件。item的 components数组用于对需要引入的js和less的文件进行描述。事实上,如果定义个模糊的路径给gulp-concat,gulp-concat会在这个目录上从上到下,从外到里进行合并文件。然而,如果得到的顺序不是你想要的,你可能需要定义得更加细致。
// page-config.js
// 文件生成的目录,如果使用本项目的node服务开发,可以直接生成到public,须在routes中配置路由
const tempStatic = 'public'
// 文件生成的目录,例如生成到java项目中,此时需要设置代理地址
const javaStatic = 'javaproject'
// 改配置用于控制js,css,的处理与合并,拷贝
module.exports = {
// browser-sync 的代理地址,可实现热更新
serverProxy: 'http://localhost:3000',
tempStatic,
javaStatic,
// 发布相关
publishPath: 'dist/',
// 静态文件地址
publishSource: [
`${tempStatic}/**/*.*`,
],
// 文件如果没有配置output,则默认放在此位置
defaultOutput: './public',
pages: [
{
components: [{
base: 'src/views/bigscreen',
// 默认会合并目录下所有的js,less
blocks: ['left', 'right']
}, {
base: 'src/components/common',
blocks: ['header', 'bottom']
}, {
base: 'src/components',
blocks: [
{
name: 'utils',
// 如果想指定合并的顺序,可以这么写。如果没有指定,会按默认顺序合并。
files: {
js: ['event', 'resize']
}
}
]
}],
page: 'bigscreen',
entryFolder: 'src/views/bigscreen',
entryFile: {
dev: 'htmlPage',
prod: 'jspPage'
},
// files 用来定义合并顺序
files: {
js: ['main']
},
output: {
js: `/js`,
less: `/css`,
ejs: `/pages`
},
ejsFormat: '.html'
}
]
}
在文件生成结果上,我定义了tempStatic和javaStatic两个变量。如果在开始阶段不需要协同java项目开发,只是写页面,可以把node服务跑起来,tempStatic 就是定义node服务的静态目录。但在跑起来之前你可能需要先设置一个路由指向生成的结果页。
而javaStatic 会指向java项目的目录,在开始对接工作后,可以直接代理到java服务地址进行开发。在跑起gulp后,src目录文件一改动,就会生成两份文件,一份到tempStatic目录,一份到javaStatic目录,你可以自行选择用哪个服务查看页面。
上面提到页面热更新的问题。在工程化开发中,修改源文件,页面通常会同步刷新,否则就只能手动按F5刷新。这个功能可以用browser-sync实现
它使用起来也很简单。利用gulp.watch,可以监听源文件变化,生成目标文件。browser-sync则监听目标文件的变化,刷新页面。
var browserSync = require('browser-sync').create();
browserSync.init({
proxy: pageConfig.serverProxy || 'http://127.0.0.1:3000/',
files: [`${pageConfig.tempStatic}/**/*.*`],
port: 8081
}, () => {
console.log('browser refreshed.');
})
let buildFiles = gulp.parallel('js', 'less', 'ejs');
let watcher = gulp.watch('src/**/*.*')
watcher.on('change', () => {
buildFiles();
});
网友评论