注意:该文件比较长,写的是从没有项目起到项目上线的一些事,从大的方面约束规范到环境的配置、代码的模式、静态文件管理都有些概括,希望对你有帮助~
项目的开发基本是 开发->测试->线上
的流程,那么项目开发前,约定好环境和域名,首先我们已知如下条件:
git
版本控制,前、后端分2个仓库(repository),会有 master线上
、 develop开发
、 release发布
3大分支 php
语言, Yii2
库 fe.com
cdn-fe.com
,线上启用 CDN
服务 /home/wwwroot/fe.com/
/home/wwwroot/cdn-fe.com/
代码目录只是个例子
域名为: fe.me
、 cdn-fe.me
前端fe维护 前端仓库
,当前如果前端也要"套模板"的话,本地也得有一套后端服务,当前数据库可以连接测试环境的
本地环境主要是前端fe开发静态页面使用,为的是方便快速开发,在 develop
分支开发并每天下班前推送到联调环境,以供后端和团队其他小伙伴及时应用最新版本
域名为: fe.dev
、 cdn-fe.dev
该环境大多数在内网,测试服务器具有前、后端独立环境,并且具有数据库,联调环境 fe.dev
迁出 develop
分支,并在每天开发者 push
的时候自动更新最新代码,后端开发静态资源连接该环境的代码 cdn-fe.dev
在每次上线前,把要上线的版本合并到 release
分支,并在测试服务器迁出 release
分支为 fe.release
和 cdn-fe.release
域名,让 qa
测试,测试通过后直接更新到线上
也就是说在这个测试服务器上具有4个站点:
这样的环境不冲突,不至于rd1和qa1在测试上线代码,而导致rd2的开发不正常,理论来说rd跟fe也一样,都是本地开发,只是rd连接的是测试环境(cdn-fe.dev)的静态文件,因为这个静态文件可以保证实时更新
域名 fe.com
、 cdn-fe.com
,当 release
版本测试通过,直接发布到线上
看着上面感觉乱乱的,其实都是配置文件,开发个 Yii2
模块,让配置为 用户配置 > 环境配置 > 默认配置
这样的规则去覆盖, 用户配置
可以用电脑主机名为 key
去设置,比如:
// 后端环境/config/默认配置.php { // 配置 "config": { // 线上默认配置 "production": { "数据库": "阿里云", "域名": "fe.com", "静态域名": "cdn-fe.com" }, // 开发环境配置 "develop": { "数据库": "内网测试机:dev", "域名": "fe.dev", "静态域名": "cdn-fe.dev" }, // 发布/测试配置 "test/release": { "数据库": "内网测试机:release", "域名": "fe.release", "静态域名": "cdn-fe.release" } }, // 当前环境 "env": "production" }
然后我fe本地的是:
// 后端环境/config/fe1.php { // 配置 "config": { "develop": { "数据库": "测试机:dev", "域名": "fe.me", "静态域名": "cdn-fe.me" } }, // 当前环境 "env": "develop" }
可见我本地有环境,但数据库我连接的是测试机的dev,而rd的本地可以是这样:
// 后端环境/config/rd1.php { // 配置 "config": { "develop": { "数据库": "本地", "域名": "fe.rd", "静态域名": "cdn-fe.dev" } }, // 当前环境 "env": "develop" }
整个配置的思路感谢 @阿旭、@消寒 大神的指导,非常好用
可见rd本地域名是自己、数据库是自己,因为这样很方便修改,而由于rd不改静态文件,那么又想保证链接最新的静态文件,那就连接测试机的dev吧,因为不管前端后端,只要往 develop
分支 push
,测试的 dev
版本就会自动更新。
当然配置式覆盖只是个思路,具体如何编写我想肯定难不倒你~
ps: 有次rd发现我个小问题,正好我也看到了,我顺手就改好了,然而rd刷新他的本地页面想稳定复现后找我来报bug,但发现我 push
后他那么好了,哈哈
.me
就是本地、 .dev
就是测试机开发分支、 .release
就是要发布啊、 .com
就是线上 cookie
不共享,避免线上出问题,本地想查却发现 cookie
共享了 前端仓库目录:
# 静态文件源码 ./src/ # 一些公用模块,包括js、css、和图片 ./common/ ./jquery.js ./zepto.js ./dialog/ ./dialog.js ./alert.js ./close.png ./popup/ ./select.js ./select.css ./base.js ./base.css # 单独的公用样式 ./css/ ./reset.css ./markdown.css # 单独的公用图片 ./img/ ./loading-16.gif ./loading-32.gif # 其他的以业务/方向名命名,比如:user、home、login ./{module}/ ./img/ ./login.png ./user.png ./page.js ./page.css # 编译后的目录,里面目录结构同src一致,方便2个版本之间的切换 dist/ # 模板文件 ./tpl/ # 公用的基础样式演示 ./commom/ # 弹出层演示 ./dialog/index.html # 其他的以业务/方向名命名,比如:user、home、login ./{module}/ ./index.html ./login.html ./xxoo.html # 单元测试 ./test/
为什么模板文件单独存放,而不是跟 src/
静态文件在一起呢?是因为模板文件最终会给后端rd并套到 php Yii2
框架里运行,前端只是本地开发方便而已
同ue、pm约定好基础样式、交互的规范,比如:
mock
数据而不依赖后端开发,达到并行开发 layout
、商家中心的 layout
本地开发时在 /tpl/*.html
里引用静态文件是:
<script src="/src/xxoo.js"></script> <link rel="stylesheet" type="text/css" href="/src/xxoo.css">
这样是可以快速开发,但由于前、后端不是一个项目目录,又不想每次修改个静态文件还需要上线 静态文件+后端文件 ,但不编译后端如何处理静态文件版本号呢?
点击这里查看静态文件版本号的处理
如果在后端项目里使用前端的一些编译语法,这样导致修改个静态文件后端就得编译,不然版本号对不上,当然你会说把后端的 View
层也放在前端项目里,做到前、后端模板分离,其实也可以,但模板里就会有些数据相关的问题,我们这里使用这样的方法处理静态文件:
php
的方法,启名为 STATIC_FILE
,后端模板(View层)里所有引用静态文件都使用该方法 release
的时候把代码编译并生成一个 md5
映射文件存放在 前端项目/static_map.php
中 <script src="<?php echo STATIC_FILE('common/login.js')?>"></script>
,文件路径基于 src/
开始,因为这样可以很好的在 src dist
两个版本切换 再配置里添加个是否使用 md5
版本和使用 src
还是 dist
的参数,如:
{ // 配置 "config": { // 线上默认配置 "production": { "static_model": "dist", "static_md5": true }, // 开发环境配置 "develop": { "static_model": "src", "static_md5": false }, // 发布/测试配置 "test/release": { "static_model": "dist", "static_md5": true } } }
这样就是线上使用压缩版本 dist
并且开启 md5
功能,而开发环境既使用开发代码 src
也不开启 md5
功能,由于测试/发布环境就是沙盒所以必须跟线上一致。
前端生成的 static_map.php
大概长这样:
$STATIC_FILE_MD5 = array( 'common/login.js' => '123456', 'user/index.css' => '123456', );
<?php
STATIC_FILE
方法大概长这样:
<?php # 假如 $CONFIG 就是配置变量,是由 【用户配置 > 项目配置 > 默认配置】 合并过来 /** * 获取静态文件路径 * * @param {string} $uri 文件uri,以静态项目里的src为起始目录 * @return {string} 文件的绝对路径 */ function STATIC_FILE ($uri) { # 静态域名 + 静态模式(src,dist) + 路径 $url = $CONFIG['静态域名'] . '/' . $CONFIG['static_model'] . '/' . $uri; # 如果没有开启md5则直接返回路径 if (isset($CONFIG['static_md5']) && $CONFIG['static_md5'] === false) { return $url; } # 处理md5版本号 # 加载前端项目编译后的md5文件 include_once(前端项目 . '/static_map.php'); $version = ''; # 如果md5版本里有该文件 if (!empty($STATIC_FILE_MD5[$uri])) { $version = '?' . $STATIC_FILE_MD5[$uri]; } # 把版本号追加上返回,当前如果不存在md5也就忽略 return $url . $version; }
这里有个问题就是说, 前端项目/static_map.php
这个配置文件,他只能跟在前端项目仓库里,如果把她放在后端仓库也那也就成了 前端改静态文件也需要上后端项目
的问题。
这样比如前端要改个样式,只需要改好测好后编译下,把前端代码一上线即可,线上 影射
文件一更新就会生成新的 md5
文件路径,比如:
前端项目里开发静态页面 <script src="/src/xx.js"></script> 后端项目里 <script src="<?php echo STATIC_FILE('xxoo.js')?>"></script>
而 STATIC_FILE('xxoo.js')
会根据环境的配置生成不同的,比如:
测试环境关闭了md5并且引用开发代码src http://cdn-fe.dev/src/xxoo.js 上线开启了md5并引用压缩代码dist http://cdn-fe.com/dist/xxoo.js?qwerty 发布/测试环境同线上一致 http://cdn-fe.release/dist/xxoo.js?qwerty
你可能会说为啥不是 xxoo_qwerty.js
呢?我想说你随便啊,改这个不过就是改下编译脚本和 STATIC_FILE
方法而已~
前端使用 requirejs
开发,页面中始终加载一个入口文件,这个入口文件在 src
里只是个加载器和项目配置,而在 dist
环境就是一些公用某块打包合并之后的,这样可以减少请求,通常这个引用是在公用的 layout
里,比如:
<body> 这里是其他的block <script src="<?php echo STATIC_FILE('common/main.js')?>"></script> ... <script> require(['home/index', 'common/xxoo']); </script> </body> </html>
src/common/main.js
文件内容是:
// requirejs代码 // ... //requirejs配置 requirejs.config({ // 默认主路径是src/ baseUrl: '../', // 其他的路径映射 paths: {}, //... });
而 dist/common/main.js
文件是这样:
// requirejs代码 // requirejs配置代码 // jquery.js // util.js // ...
当然你可以有很多公用文件,比如频道的公用文件、某模块集合的配置文件,我们在开发时全使用异步加载,在发布、测试时前端使用脚本编译处理下,当然编译前/后的模块路径不换,也方便文件定位
前端项目配置在 /package.json
里,大概如:
name": "前端项目", "version": "1.0.0", "description": "xx网前端项目", "srcipts": { "server": "http-server -p 8080", "start": "npm run server", "test": "mocha --reporter spec --timeout 5000 --recursive test/", "test-cov": "istanbul cover _mocha -- -t 5000 --recursive -R spec test/", "fecs": "fecs check src/ test/", "release": "", "watch": "", "debug": "" }, "devDependencies": { "http-server": "*", "mocha": "*", "istanbul": "*", "fecs": "*" } }
{ "
说下几个命名:
npm run server, npm run start, npm start
- 本地开启 web server
功能,用来开发静态页 npm run test
- 使用 mocha
运行单元测试 npm run test-cov
- 使用 istanbul
运行测试覆盖率 npm run fecs
- 使用 fecs
检查代码规范 npm run release
- 编译发布代码,把 src/
文件编译、混淆、压缩、合并到 dist/
目录里,把 dist/
目录里的所有文件生成 md5
并生成 static_map.php
npm run watch
- 本地监听静态文件修改并实时刷新浏览器 npm run debug
- 本地开启 web server
,配置 host
修改把线上域名 cdn-fe.com
域名到本地环境,并可配置 dist->src
或者 src->dist
的映射,方便调试线上代码 至于 watch
、 debug
、 release
这些脚本,我想你可以根据你的项目写出来,但不使用全局的包,目前 webpack
、 gulp
都支持非全局使用
这里的开发流程只是说前端的一些流程工作,不包括诸如跟pm对需求这些
develop分支:根据psd确认稿开发成本地的 .html
文件,可以使用 npm run *
的一些命令更好的本地开发,必须在文件内写好相关注释,开发完成(自测通过)后可在测试静态环境(cdn-fe.dev)让ue、pm确认效果,当然这里也只能确认下效果,逻辑还得出整个测试环境才可以测,在这里确认效果方便fe修改,不然套完模板告诉你有问题你就哭吧
develop分支:把静态项目里的 .html
文件代码片段根据注释编写出后端 View
层代码,并写相关的逻辑处理,某些功能告一段落后可以让联调
在准备上线时把前端代码编译处理,再把开发分支代码合并入 release
分支,推送到测试机,让qa测试该版本的 release
代码,通过后给该版本打上标签,并合并入 master
、 develop
线上永远是 master
,只要合并入 master
分支表示代码没有问题,上线可使用 线上机器
拉分支,或者 .tar
包上线,当然这些看你如何处理了,线上只要一更新到 master
代码,就表示项目上线
前端项目上如果发现线上问题,可在本地把 master
迁出一个 fix-*
分支,可以使用 npm run debug
命令把线上压缩代码重写到本地开发代码以方便调试,代码没问题后,合并 release
,并测试,通过后合并到 master
上线并打上标签,并合并到 develop
npm run
功能,杜绝使用全局包(开发只需要克隆仓库和 npm install
安装依赖即可 md5
,而不用担心上线需要编译后端模板 session
单点服务器,可以相应的调整下配置的方案 md5
映射 你会不会说为啥感觉这么多额,其实当你整个走下来也没什么,至于说不用 requirejs
而用 commonjs
或者 es6
啥的,亦或者说用 fis3
,使用 react
不使用 smarty
之类我认为大的流程上都是大同小异,开发模式很多,好的不一定适合自己项目~
当然可能考虑的还不够多,欢迎吐槽~