首先我是很赞同业界的前后端分离的开发模式,虽然现在都讲究全栈工程师,但是毕竟术业有专攻,前端同学专注多终端,后端同学关注高性能高可用。大家各自再自己的专注点上发光发热。
想想我们以前分模块开发,既写java又写jsp,高级点的jsp不写逻辑,所有的交互都是异步交互,算是一个简单的前后端分离模型,最后找个美工(对,不是前端是写css或者会画图的美工画两个图)美化一下,然后就可以用起来了,这样的模式简直就是原始社会一样。
目前我同时接手了前后端同学给我的2份代码后,一个人做起了前后端分离开发,我感觉自己一下子高大上了起来,但是有几点我也要吐槽一下
1我要维护2分代码,一份用webstorm编译js代码,一份用intelidea开发编译java代码,同时开了java和node服务本地联调,这2个服务光开起来就已经7G内存了(jvm我开的是1024M,因为需要加载对象内存处理)。可怜的X1的内存是焊死的…焊死的….,而且只有8G….基本再开chrome就卡死了,卡死了。。。
2 本地开发模式是这样的,前端代码用node开启一个server跑页面,后端代码开启跑接口服务,用页面调用后端的接口服务,这就遇到一个尴尬的js跨域调用服务的问题,还好chrome良心支持这个参数,又还好IE我们已经放弃了。。。
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --args --disable-web-security --user-data-dir
但是由此升级chrome到51这个版本,新浏览器又出现跨域调不通的问题了,那时我的世界是崩溃的,以后怎么开发吖
还好网上有解决方案,感谢万能的google,对于新版本的chrome浏览器,需要额外增加user-data-dir,然后就可以继续愉快的写代码了
这里我还要吐槽下以前的npm脚本
"scripts": {
"clean": "./node_modules/.bin/rimraf build",
"build:webpack": "NODE_ENV=production ./node_modules/.bin/webpack --config webpack.config.prod.js",
"build": "npm run clean && npm run build:webpack",
"mock": "MOCK=true npm run start",
"start": "./node_modules/node/bin/node server.js",
"lint": "./node_modules/.bin/eslint src",
"lintfix": "./node_modules/.bin/eslint src --fix",
"daily": "npm run build && git add -A && git commit -am 'deploy test' && git branch -D daily/9.9.9 || true && git branch daily/9.9.9 && git push -f origin daily/9.9.9 && git reset --hard HEAD~"
},
看里面的反斜线,好像windows都不能用吖,只能自己搞个bat脚本封装下,基本上再window下告别npm命令了
echo "====start daily publish"
call .\node_modules\.bin\rimraf build
set NODE_ENV=production
call .\node_modules\.bin\webpack --config webpack.config.prod.js
call git add -A
call git commit -m 'dailypublish'
call git branch -D daily/9.9.9
call git branch daily/9.9.9
call git push -f origin daily/9.9.9
echo "====end daily publish"
3 最后吐槽一下发布和回滚问题
有段时间需求实在太多,团队增加一个同学一起开发,注意下前端这块,我们都是用分支开发,发到预发的时候代码是都要合并到daily9.9.9这个分支的,然后触发一个钩子,这个钩子会把这9.9.9的代码放到cdn上,就是2个会合用一个分支,预发环境经常是代码被各种冲掉,这个后端的开发和发布系统支持的就好,环境只有一个,但是每次发布只能发一个分支。这样可以各种切换,而不是暴力的合并
另外,由于后端代码一次发布可能会有多次的前端发布,所以前端的版本号其实是和后端的版本号不一致的,如果线上出了故障,后端代码进行回滚我可能准确的回滚到一个版本,但是前端代码的版本号是跳跃的,很难回滚到后端同一时刻的版本
4 最后就是接口和代码设计的问题
由于前后端代码是不同同学开发的,当前端A同学需要一个列表数据会跟后端B同学要一个get接口,这时候B同学提供一个接口服务返回一串数据给前端,我看过一个之前的代码前端拿到这个数据活生生的在前端做了一个排序,各种map各种比较,其实这个在后端数据库层面或者内存层面做一下非常简单。
5 最后讲讲编译问题
之前我手上还有一个项目,也是前后端代码分开的,这个比较特殊,前端是GXT写的,恩就是用java写的EXT,写前端的页面的时候非常痛苦,GXT的编译特别慢,有的时候改一个页面编译一下要1分钟,另外发布的时候非常原始,写好GXT的代码把代码打包成war包,然后copy出里面的静态页面再放到后端代码里,后端代码再打成war包进行发布
相比现在来说现有项目已经很好了,前端写好代码push到指定分支上就能自动部署到cdn上,然后后端的vm直接读取cdn上的静态资源。但是后端的发布往往要等cdn部署完毕才能真正生效,根本原因还是不是引得本地文件
因为实在感觉现在本地开发模式效率有点低(真正项目里我们还是要做前后端分离的哈),我花了2天的时间对现有的项目进行了一下改造,就是将前后端代码合并起来,这里就简单的介绍下如何用再一个项目里同时维护前后端代码
这里涉及到webpack打包操作,用mvn进行npm操作,前台代码的热部署及前端代码的合并分发
1 线上改造后的代码结构
其中node是maven下运行npm的插件引入的,node_modules是前端依赖包(可以理解成java中maven引入的本地仓库),将原有的前端文件放到了webapp中
其中build是webpack打包生成的输出文件,index页面引用的就是这里的合并后的js和css,app.js是前端的入口文件
其他文件就是后台和前端的配置文件了,前端的主要打包文件是webpack.config
2 定义npm的打包命令
"mydaily":".\\node_modules\\\\.bin\\webpack-dev-server --config webpack.config.js --inline ",
#"mydaily":".\\node_modules\\\\.bin\\webpack --config webpack.config.js --hot --progress --colors --watch",
"mybuild":".\\node_modules\\\\.bin\\webpack --config webpack.config.js --output-public-path /build/",
"myclean": ".\\node_modules\\\\.bin\\rimraf .\\src\\main\\webapp\\build",
"mystart": ".\\node_modules\\node\\bin\\node server.js",
其中mydaily定义的的是的本地开发模式,mybuild是打包线上发布文件,myclean是清除文件,mystart是为了兼容前端开发同学保留的命令,直接用node本地启动服务,当然还有一些其他的调用eslint等辅助控件这里就不一一列出了
3 本地开发模式下如何引用前端输出的静态资源呢
indexvm里是这么写的
## <link rel="stylesheet" href="http://localhost:8080/build/style.css"/>
## <script src="http://localhost:8080/build/vendors.js"></script>
## <script src="http://localhost:8080/build/app.js"></script>
这里有个关键的启动命令,本地在npm的时候使用的是webpack-dev-server。这个命令可以虚拟出一个服务,并且配置了热加载,我们可以看到文件的publicpath配置的就是8080端口下的这个地址
output: {
path: path.resolve(__dirname, 'src/main/webapp/build'),
filename: '[name].js',
publicPath: 'http://localhost:8080/build/',
},
如果是线上发布,就直接启动webpack,将文件编译好发布到build文件夹
4 如何做前端资源热加载的,这里有2个地方要配置下
一是使用一个jsx的loader使用的react-hotloader
二是配置idea的自动监听功能
这样就可以做到热部署了
5 如何用maven维护npm的打包和编译呢
这里就要提到mavne下一个插件了frontend-maven-plugin,因为无论是线上aone打包还是线下打包其实调用的都是mvn clean install命令,这时候会自动触发这个插件中的命令,我本地的配置如下
<!--前端打包-->
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>v5.2.0</nodeVersion>
<npmVersion>3.3.0</npmVersion>
<nodeDownloadRoot>https://npm.taobao.org/mirrors/node/</nodeDownloadRoot>
<npmDownloadRoot>http://registry.npmjs.org/npm/-/</npmDownloadRoot>
</configuration>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm run build</id>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run mybuild</arguments>
</configuration>
</execution>
</executions>
</plugin>
这个插件会在maven命令执行的时候自动执行配置好的npm命令,所以在打包的时候就会自动触发npm run mybuild命令打包最新的静态资源到war包中,这样就无需在引用cdn中的文件了
经过以上5部改造,基本上可以实现前后端代码同时维护和开发,保证了本地开发的效率。但是未来多端及服务化,前后端分离还是大趋势,我们还是要尽量摒弃小作坊的开发模式,让代码在稳定的基础上最大的保证开发效率。另外还是要像全栈开发努力,因为很多功能前端做起来很容易,但是后端要写一大堆不可维护的代码来实现,有的时候前端要做很复杂的代码,后端可能一个sql就搞定了。
转载于:https://my.oschina.net/zimingforever/blog/725104