Closed fouber closed 2 years ago
工作5年了,一直处于公司需要什么研究什么的的状态,一直没仔细认真的去研究过某项东西,之前做的项目都是基于局域网的管理系统,现在准备做web项目,但是从来没设计过这方面所以有些不知所措,不知道该怎么做,后来通过网络了解了前端模块化的概念,也使用了seajs等,最近有开始接触fis打算想把这两个混合用,但是不知道怎么下手,不知道楼主有没有什么好意见
@lucifercha 我来凑个热闹。
不建议将 seajs 与 fis 混合在一起用,建议用 webpack + fis3
seajs 后续衍生了 spm , spm 后续因为webpack, spm 停止维护了。
@nimojs 好的谢谢 我研究研究
不了解 fis 的 map.json 的请点击此处
以前前端静态文件是与后端 server 一起发布的,现在有一个服务器可以用于做专门的静态资源服务器。
目前想法:
基于map.json 后遇到问题如何做版本回滚?
没配置过独立的前端静态资源服务器,希望各位能分享出自己团队的做法和给我一些建议。
@nimojs
可以新开issue。。。
发布静态资源看你们自己的部署方案吧。一般是公司内撘一个ci系统,比如jenkins,然后在上面安装运维提供的部署脚本,然后配置gitlab(通常不用github,防止泄密)的webhook,一有提交就发请求到jenkins上,jenkins拉取代码,调用fis构建,然后把产出的代码通过运维脚本推送到测试或者生产环境。大致的流程是:
运行效果:
上图中的SCRAT是我们基于FIS定制的自己的工具
总之效果就是【提交代码】→【自动部署】,【自动部署】包括了【构建】+【代码推送】
其实每次发布,都可以把构建好的代码生成一份tar包存到代码库里,生产/测试/开发环境可以自由切换任意版本的包。服务端的包自然携带了map.json,切换哪个就代表了回滚哪个。静态资源不用回滚,丢在静态资源服务器就好了
@fouber 在 fouber/blog 新开 issues 么?
感谢回复,目前我们没有运维人员。
考虑使用 githook master分支同步部署
本地 fis 构建 -> 提交构建后的代码 -> githook部署
版本回滚通过回滚后端中的 map.json 实现。
区别于 server 构建缺点应该是在 git 中会存在很多构建后的 md5后缀文件。
对于这些 jenkins
运维脚本
都完全不了解,公司也没有相关的运维人员。小型团队的前端开发人员想要构建一套代码发布系统应该通过哪些渠道和学习哪些知识可以做到这件事?
这里的运维脚本包括中 fis 的构建代码么?
或者使用另外一种手动发布的方案
前端生成环境使用git/svn,需要发布时使用 fis 的deploy-部署配置 和 fis-deploy-git 手动发布构建后的代码到前端静态资源服务器。
没有运维人员的情况下就做好版本控制和能快速控制版本回滚。
有一些低成本的做法,借助git:
release
:包发布仓库,用于管理包和回滚source
:源代码仓库,用于开发在 source
仓库中准备一个 release.sh
脚本,大致的内容是:
fis release -Duolmpd ./output # fis构建到output目录
cd output # 进入output目录
pack_time=`date -d now +'%Y%m%d%H%M'` # 构建时间
pack_name=build-$pack_time # 压缩包名称
tar zcf ../$pack_name.tgz * # 打一个压缩包,带时间戳的
cd .. # 回到上一级目录
rm -rf output # 删除output
git clone ``你的release仓库`` # 克隆release仓库
cd release # 进入目录
mv ../$pack_name.tgz . # 把之前打的tgz包贴过来
git add -A && git commit -am "xxx"
git push origin master # 提交
release
仓库中准备一个 deploy.sh
脚本,你可以给它传参数,指定某个具体的tgz文件,这个sh脚本的功能就是解压缩对应的代码包,然后把内容推送到部署服务器上。你的 source
仓库看起来内容是:
source
├─ components
├─ views
├─ server
├─ release.sh
└─ fis-conf.js
你的 release
仓库的内容大概是:
release
├─ build-20150328143321.tgz
├─ build-20150410162404.tgz
├─ build-20150628203349.tgz
├─ ...
└─ deploy.sh
要上线(或回滚)什么包,就在release仓库下执行:
./deploy.sh build-20150410162404.tgz
webpack+gulp,基本可以解决模块打包和上线的问题了 :smile:
@fouber
关于 release
source
git 低成本方案。
回滚可以通过操作后端服务器中 map.json 控制,那么 ./deploy.sh build-20150410162404.tgz
的操作是否可以省去?
而 release
仓库直接就是正式环境 git
@jialezhang
webpack和gulp都只是构建工具,上线部署和包管理还需要额外的工作
@nimojs
release是保存各种历史发布包的仓库,你需要这个仓库以方便快速回滚啊,map.json只是资源表,回滚不仅仅回滚前端资源表,还有你的后端模板也可能需要一并回滚
@fouber 明白了,原先我的想法是正式的静态资源服务器上的内容只增加不删除。所以想以 map.json 作为前端版本控制核心。
@nimojs 静态资源服务器上的内容可以只增不减,但你的服务端模板以及模板所使用的map.json还是需要整体部署或回滚,只改map.json可能会导致模板与静态资源内容不匹配而报错
@fouber
那么构建后的前端静态资源文件是必须做版本控制以方便回滚?
构建后的前端静态资源文件可以通过 *.tgz
的方式备份?
看来还是 有一些低成本的做法,借助git 方式最合适。
按照这个方法,每次版本更新需要开发人员在 release 仓库运行 ./deploy.sh build-20150410162404.tgz
?
@nimojs
如果你的静态资源服务器和模板服务器是不同的webserver,比如静态资源要推送到七牛上,那么你可以:
@fouber 感谢 我们 php server和 static server 是分开的。
那么最终可以采用:发布到测试环境时提交后端模板、map.json 、执行 deploy.sh 发布静态资源到static server。
测试环境发布到正式环境由后端解决,而前端资源在发布测试机时就已经部署好了。
@fouber 感谢,我这里现在还没有包管理的需求(主要是太小了....),暂时webpack和gulp直接可以解决上线部署的东西,不过看了这些开阔了视野了!!!
楼上的各位讲的都太高大上 看的云里雾里的
@jialezhang 上线部署是指项目构建之后,需要把构建好的代码上传到服务器上,上传的过程有些团队用的是ftp,有些用的是rsync,这两种方式有对应的gulp插件,个人开发可以直接上传。不过对于团队要长久维护一个大一些的项目,上线/回滚是很常见的运维操作,每次部署的历史版本都应该保留,在新版本有问题的时候方便立刻恢复之前的版本,在服务器挂掉之后方便立刻部署到其他机器上。
多谢 @fouber 大神讲解!这些东西估计要等到有好几个人一起开发才需要了
@fouber 重新整理了下思路,请帮忙看下如下方案是否靠谱:
(以下源码指的是未处理的 less sass 等文件)
这样源码在 git中做版本控制。需要回滚就回滚 map.json。(其实就是 fouber 给出的第一个方案中去掉 jenkins 的版本)。开发人员只关心2个步骤 【本地编码看效果】 -> 【GIT RP 到 master】
但是 在 server 运行 fis 构建后得到的 map.json 如何发布到后端服务器我不知道怎么做合适。
目前想出2种做法:
@nimojs 你没有使用后端模板吗?如果使用了,每次回滚map.json也要回滚模板的。
关于map.json推送服务器的问题,可以考虑用rsync,建立两台机器的信任关系,然后rsync推送
@fouber 恩,使用了后端模板。版本回滚回滚所有后端代码和 map.json ,我将 map.json 理解为前端资源在后端的集合。
@jialezhang 能交流一下你们webpack+gulp的工作方式吗?
@Jokcy webpack:管理JS之间的依赖,(写React的时候很爽 hot-loader); 会用ES6,webpack上babel。 gulp: SCSS预处理(之前会处理coffee),后期静态资源链接替换(gulp-rev)。 当然webpack的功能远不止如此.....我只是用了冰山一角
有没有介绍FIS的灰度发布相关的内容
我理解下来,灰度发布可以通过类似于<%require_js("core:core.js")%>这样的require_js方法来控制读取不同版本的文件。同时,获取mapjson的时候也需要返回不同版本才行。想法不太成熟。
有没有介绍FIS的灰度发布相关的内容
@feifeipan https://github.com/fouber/blog/issues/6
问下楼主一般网站的主页静态页面是自动生成的还是通过后端管理系统手动生成的,还有现在一般用什么方式生成静态页
民工兄,最近一直也在思考前端构建的问题,你的文章里面涉及到静态资源更新似乎都是可以直接更新整个html文件的,但是如果不是html,而是php之类的文件,而且这些文件是由后台的程序员来更新和维护(也就是说前端工程师没办法直接更新php文件),那么涉及到一些静态资源的更新就没办法那么简单的直接替换静态文件的链接了,每次md5之后还需要告诉后台来更新链接,请问有什么好点的解决方法吗。
@a-lian123
前端工程师应该争取模板及模板引擎的控制权!!!
写php的模板对于前端工程师来说没什么难的吧,不过确实很多公司对这个是抓住不放的,会有“静态页面模板化”这样的研发流程,这种流程其实非常反工程,不然也不会有这么多有关“前后端分离”的讨论。
不吐槽了,我先假设你们团队由于某种不可抗力确实无法把“静态页面模板化”的流程从整个研发环境中剔除,然后给出一些我的意见。
首先,假设你们的前端项目只有三个文件:index.html、index.css和logo.png。其中index.html代码中写了对index.css和logo.png资源的引用,形如:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
...
<img src="logo.png" />
</body>
</html>
基于我其他文章说到的静态资源更新思路,通过实现给文件添加指纹来解决资源缓存问题,这样,你的html构建之后应该变成:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/public/css/index.a8f79ad.css">
</head>
<body>
...
<img src="/public/img/logo.053a8e6.png" />
</body>
</html>
如果把以上代码发给后端去做“模板化”,很明显,当项目仅更新了css文件之后,由于资源的md5戳改变,html中的资源引用会发生更新,就不得不让后端再搞一次“模板化”,他们知道你只是修改了css,html又没变过,肯定不理解为啥还要再模板化一次,觉得前端都是傻逼。
你的目标其实是:
如果项目迭代只是修改了静态资源,而没有修改主文档模板,应该不需要再次进行模板化的研发流程
按我经常絮叨的那套东西来说,解决这个问题的方案就是——基于表的静态资源管理系统。
回到最开始的前端HTML页面代码:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
...
<img src="logo.png" />
</body>
</html>
调整你的构建工具,使得最终产出结果并不是在页面上直接引用带md5戳的资源,而是变成这个样子:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="<?= uri('logo.png')?>">
</head>
<body>
...
<img src="<?= uri('logo.png')?>" />
</body>
</html>
即把你交付后端做模板化的页面变成一个PHP代码,替换源码中的资源定位,将其变成一个php函数调用。
相应的,你的源码目录结构可能是这样的:
src
- index.html
- index.css
- logo.png
而构建之后的结果是:
src
- index.php
- public
- css
- index.a8f79ad.css
- img
- logo.053a8e6.png
- map.json
其中public目录部署到静态资源服务器,index.php交给后端做最终的模板化,而map.json就是我说的“资源表”了,内容大致为:
{
"index.css": "/public/css/index.a8f79ad.css",
"logo.png": "/public/img/logo.053a8e6.png"
}
好了,现在你想办法说服你们后端工程师,在php中添加那个 uri
函数,其代码大概是:
function uri($id){
$map = json_decode(file_get_contents('map.json')); //此处可优化
return $map[$id];
}
也就是说,页面上的资源地址,变成通过读表动态输出。这样,你们每次项目迭代,如果没有修改模板,只要更新静态资源和资源表,php模板就能正确加载更新的资源了。
列一下这个方案的改造成本:
上面的清单前4项都是可以控制在前端内的工作,只有最后一项需要后端配合一下,但其逻辑其实非常简单,就是查表返回资源的部署路径,不会带来多少性能负担,却可以实现缓存控制,提升页面性能,相信有足够的理由推动其实现。
最终完成以上工作之后,前端再发布就不用担心资源引用问题了,因为你们可以通过更新资源表实现页面资源的更新,模板文件不用二次处理。
以上方案其实算是比较折中的办法,在后端的威压下委曲求全的结果。我觉得最好的实现还是想办法争取模板及模板引擎的控制权(重说三),将“模板化”的流程彻底从整个研发过程中剔除掉,比较容易针对前端做更多的性能优化策略,定制更加合理的组件化开发方案。
毕竟大家都是为了项目好,谁也别惯着谁。
赞同,前后端谁的话语权大,谁的项目就更好组织和架构。努力成长为全栈吧
支持 基于表的静态资源映射系统
FIS的亮点在于静态资源表,而绝大部分场景都需要与后端模板结合才能发挥最大的价值。但发现很多团队还是前端写HTML交付给后端的工作流程。
基本上高效的团队都是前端控制后端模板,而一些小团队不能实现前端控制View我觉得主要原因在两点:
我目前是用自己写的 mock server 实现前端在Node 中写页面渲染配置,然后本地的PHP 127.0.0.1:1234 端口提供一个 PHP Smarty 渲染接口。
配置代码
$.page({
title: '退订',
url: '/unsubscribe/',
template: 'www/unsubscribe.html',
data: {
email: 'mail@qq.com'
}
})
模板 www/unsubscribe.html
email: <input name="email" value="{{$email}}" />
<input type="submit"/>
当用户访问 127.0.0.1:3000/unsubscribe/ (node server)时 node 会将 url template data 都 post到 127.0.0.1:1234 然后 127.0.0.1:1234 直接执行PHP Smarty 渲染返回HTML。
最近跟一些朋友交流的时候发现其实他们是有后端模板的控制权的。都是先写HTML交付后端,然后后端转换为后端模板后就必须在PHP 环境中写模板了,但是因为没有 mock server 的支持后期维护非常麻烦。
我们是所有数据都在mock server 中模拟好,最终只交付给后端文档和模板。fis-plus 好像是 Java 调PHP实现的,但也都是可以在本地模拟后端模板渲染的。
—
其实去年也就请教过了 fouber 关于前端写模板的事,那时候是在 node 中解析 handlebars ,然后让后端用 php 版的 handlebars 。也是个坑,fouber 当时也提醒过了,后来参考fis-plus 才想到可以直接让PHP解析模板。node 的 mock server 当做一个中间层调 php 接口。
因为我是实现后端模板渲染接口的方式来模拟页面渲染,理论上是支持任何后端模板渲染的。我想将前端控制模板层的解决方案和mock server 向社区推出去。发现 fis 在后端模板和前端工程的结合太赞了,不知道我这种node 做中间层调 php 直接渲染模板的方式会不会在某些业务场景下不能跟前端工程结合好。(目前我只是用 smarty 读 map.json 让资源 md5 化)
因为之前两个语言版本的 handlebars 共用就是个坑,还踩过用js版本的smarty 的坑。虽然目前这种方式没有遇到任何不爽的地方,但还是希望 fouber 能帮看下有哪些地方会坑。
@nimojs
你现在的实现方式也可以,只是可能稍微有点绕。其实可以考虑直接用php 5.4之后内置的webserver进行调试,没有必要多余一层nodejs了
@fouber 这么详细的回复,太感谢,项目最近才接手,因为历史原因,暂时无法直接由前端来开发模板。这两天着手来试下这种解决方案,后期争取能进行分离。多谢!
@fouber 指的是这个?
php -S 127.0.0.1:1234
我现在也是用 php -S 启动内置 server 的,不用node 直接在 php -S 对应PHP文件写 php 代码渲染页面么?
//$view( url, 数据 ,模板)
$view('/url/','{"email":"mail@qq.com"}', 'www/index.html')
用node 多一层是因为要加可视化控制AJAX的功能
和根据配置用 Node 生成简单的文档
$.get({
title: '任务统计报告点击详情',
url: '/ajax/get_report_click_detail/',
request: {
id: '23',
_id: '任务 id',
url: 'http://cunog.com/wprr',
_url: '点击地址'
}
}).ok({
view: [
{
datetime: '2014-12-23 14:23:32',
email: 'mail@qq.com',
id: '122.132.113.11',
count: 3
},
{
datetime: '2014-12-23 14:23:32',
email: 'mail@qq.com',
id: '122.132.113.11',
count: 3
},
{
datetime: '2014-12-23 14:23:32',
email: 'mail@qq.com',
id: '122.132.113.11',
count: 3
},
{
datetime: '2014-12-23 14:23:32',
email: 'mail@qq.com',
id: '122.132.113.11',
count: 3
}
],
pagecount: 10
}).error({
status: "error",
msg: "Error detail"
})
$.page({
title: '企业信息完善',
url: '/system/company_info/',
template: 'system/company_info.html',
data: {
address: '公司地址',
company_name: '公司名称',
website: 'http://www.baidu.com',
tel: '24242',
name:' 联系人姓名',
qq:'23242',
industry: [{key:"1", value:"汽车制造与销售"}, {key:"2", value:"生物医药与保健品"}, {key:"3", value:"广告与传媒", checked:true}, {key:"4", value:"房地产开发与管理"}, {key:"5", value:"消费电子与计算机"}, {key:"6", value:"软件与系统集成"}, {key:"7", value:"半导体与电子元器件"}, {key:"8", value:"通信制造与运营"}, {key:"9", value:"材料与包装"}, {key:"1", value:"机械设备"}, {key:"1", value:"能源与采矿"}, {key:"1", value:"纺织服装"}, {key:"1", value:"物流与后勤"}, {key:"1", value:"金融服务"}, {key:"1", value:"零售业"}, {key:"1", value:"烟草酒业"}, {key:"1", value:"家用电器"}, {key:"1", value:"食品饮料"}, {key:"1", value:"农林牧副渔"}, {key:"2", value:"教育培训"}, {key:"2", value:"公共事业服务"}, {key:"2", value:"化学工业"}, {key:"2", value:"日用化工"}]
}
})
我现在是将mock server 直接放在前端的一台服务器上,然后给后端看前端模拟出来的所有页面交互。
@nimojs
php -S localhost:8000 router.php
这种模式下所有请求会转发给router.php处理,然后你可以在router.php中实现一个路由规则,把你们线上的URL规则在这个router.php中都体现出来
:ok_hand: 理解了,原本 node 所处理的路由都可以由 router.php 处理。 如果直接用 php 等于也是可以用 php -S 启动一套类似下面语法的自己实现的 mock server 对吧
$view('/url/','{"email":"mail@qq.com"}', 'www/index.html')
@nimojs 是的。原理都是一样一样的
目前大多数前端team都在采用模块化[amd/cmd]方式开发,现在前端脚手架这么多,打包部署发布流程也都并行不悖。目前webpack也有很大的气势,与grunt/gulp相比大家觉得优势在哪?未来脚手架还会有怎样的革新或优化?
@heicx
grunt/gulp只是一张白纸,webpack起码针对前端了。
目前我觉得 combo url
+ scrat.js
这样的方案才是最好的,根本就不需要打包合并文件嘛。有了一份给浏览器的依赖表,基本就足够了。不知道的 @fouber 在这个实践过程中有遇到什么坑?
@jialezhang
主要问题还是combo url过长吧,到说不上危害,只是可能会导致某些页面变成两个请求而一定程度上可能
影响性能
@fouber 当一个 loader 基于 资源表实现了 combo url 和 localstorage 缓存后是否可以不使用构建工具的本地打包功能了?(除了会出现变成2个请求)
不应该是@ 我嘛😭。
的确,对于浏览器根据url
进行命中缓存来说,是不太友好的。
不过良好地请求分割,应该是可以提高命中缓存的概率的吧。例如:combo(框架库.js + 插件.js); combo(页面单独的功能.js+其依赖.js)。
嗯,url 真的超过了限制,这个应该要在loader里面也进行下处理吧。~
@nimojs 本地打包应该是可以剔除了的。loader
也是可以处理成两个请求的,就看你要的配置要怎么给到loader
了
@jincdream 我心中理想的代码打包是这样的
base.js (loader.js 高度复用的基础库) page.index.js (页面所需JS,只涉及组件调用代码) combo资源 (page.index.js 所需的所有模块)
我也是不喜欢用本地打包,这样开发人员只用写 base.js 和 page.name.js
你现在的loader用的是什么?
可以看下scrat的webapp模式,跟你需要的打包方式差不多。
发自我的 iPhone
在 2015年9月8日,19:19,Nimo Chu notifications@github.com 写道:
@jincdream �我心中理想的代码打包是这样的
base.js (loader.js 高度复用的基础库) page.index.js (页面所需JS,只涉及组件调用代码) combo资源 (page.index.js 所需的所有模块)
我也是不喜欢用本地打包,这样开发人员只用写 base.js 和 page.name.js
你现在的loader用的是什么?
— Reply to this email directly or view it on GitHub.
恩,这个repos虽然命名是blog,一开始也定义为我的个人博客,但感觉光我一个人码字也挺空虚寂寞冷的,所以希望有在前端工程方面遇到问题,或者有所感悟,或者有所实践的同学,可以尽情在issues里开启话题来与大家分享交流,有个比较集中的地方讨论有关前端方面的工程问题也挺好的不是~~