mambat / blog Goto Github PK
View Code? Open in Web Editor NEWmambat - 博客
mambat - 博客
团队并行开发多个功能,这些功能有可能是跨版本,如何才能既保证跨版本的代码不影响当前版本、又保证跨版本功能的正常开发和协作?
生产环境发现严重 Bug 需要立即修复,而当前版本的代码已提交 master 分支、且并未测试充分,这时该如何处理?
交给你的新功能已经开发完毕,但最终删掉了这些新功能,如何才能将回退成本降到最低?
利用 Git 强大的分支,可以帮助我们很好的解决这些问题。
有个很成熟的叫 Git Flow 的分支模型,能够应对 99% 的场景。简单来说,Git Flow 就是给原本普普通通的分支赋予了不同的职责。
master 和 develop 被称为主分支(main branches)。
master 分支上的代码应该是可以随时发布生产环境的,即 “production-ready”。
develop 分支上的代码应该是 upcoming release 所需要的最新的代码,也称为 “integration branch”。
为了做到 并行开发、跟踪新功能的开发、生产打包、快速修复线上Bug,还需要一些辅助分支(supporting branches)。
辅助分支都是临时性的,最终都会被删除。
辅助分支从技术上来说,跟主分支没有任何区别,唯一的区别在于,我们赋予了它们不同的职责。
Branch off from:
develop
Merge back into:
develop
Branch naming convention:
除了 master, develop, release-, or hotfix- 都可以,最好是 feature-*
Feature branches 有时也称为 Topic branches,用来开发新功能,在创建时可能并不清楚该功能属于哪次发布版本。
创建 Feature 分支:
$ git checkout -b myfeature develop
如果新功能属于 upcoming release,开发完成后需要将其合并到 develop 分支:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop
Branch off from:
develop
Merge back into:
develop and master
Branch naming convention:
release-*
当 upcoming release 所包含的新功能已全部开发完成、且达到稳定状态(测试通过)时,就可以从当前 develop 分支创建新的 Release 分支,用于发布生产环境。
Release 分支只允许进行小的 Bug 修复 以及 一些元信息(meta-data )的修改,比如版本号、构建时间等,原则上不允许再进行新功能的开发。
将用于发布生产的 Release 分支一旦创建,就代表着 develop 分支可以接受 next release 所包含的新的 Feature 分支的代码合并了。
创建 Release 分支:
$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2. This can of course be a manual change
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)
当 Release 分支已经达到发布要求时,需要将其合并到 master 和 develop 分支。
合并到 master 分支,同时打 tag:
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2
合并到 develop 分支(可能会包含 bug fixes 代码 和 更新后的 meta-data):
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
发布验证成功后,删除 Release 分支:
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).
Branch off from:
master
Merge back into:
develop and master
Branch naming convention:
hotfix-*
当生产环境出现严重 Bug、需要立即修复时,就需要从 master 分支对应的线上 tag 检出 Hotfix分支、进行 Bug 修复。
创建 Hotfix 分支:
$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)
解决 Bug、提交代码:
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
跟 Release 分支一样,最后需要将 Hotfix 分支合并到 master 和 develop 分支:
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
特别注意
,当存在 Release 分支时,需要将 Hotfix 分支合并到 Release 分支而不是 develop 分支。
首先 Release 分支上是即将发布生产环境的代码、需要包含这次修复Bug 的内容;其次 Release 分支在发布生产环境后、最终还是要合并到 develop 分支。
如果 develop 分支急需这些修复 Bug 的内容、无法等待 Release 发布,也可以立即将 Hotfix 立即合并到 develop 分支。
发布验证成功后,删除 Hotfix 分支:
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
git-flow cheatsheet
Issues with git-flow
gitflow consider harmful
非功能性需求(Non-Functional Requirements ,NFRs)的概念非常宽泛,从易用性到安全性都属于非功能性需求,现将我所了解的非功能性需求整理如下。
使用开源工具redis-rdb-tools
rdb -c memory dump.rdb > dump.csv
./redis-cli -h 127.0.0.1 -p 6379 --bigkeys
参考huoding
基于redis-rdb-tools二次开发
Git是目前世界上最先进的分布式版本控制系统(没有之一)。
Linus Torvalds
- Linux & Git
- Talk is cheap, show me the code.
- Software is like sex: it's better when it's free.
版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。
版本 | 用户 | 说明 | 日期 |
---|---|---|---|
1 | 张三 | 删除了软件服务条款5 | 7/12 10:38 |
2 | 张三 | 增加了License人数限制 | 7/12 18:09 |
3 | 李四 | 财务部门调整了合同金额 | 7/13 9:51 |
4 | 张三 | 延长了免费升级周期 | 7/14 15:17 |
猛戳Here
Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。
最初,只有一台机器有一个原始版本库,此后,别的机器可以“Clone”这个原始版本库,而且每台机器的版本都是一样的,没有主次之分。
然而,实际情况往往是找一台电脑充当服务器的角色,7x24小时开机,交换大家的修改。
猛戳Here
每个版本库都有一个 .git 目录,它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆版本库的时候,实际拷贝的就是这个目录里面的数据。
从版本库中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。
所谓的暂存区域只不过是个简单的文件,一般都放在 Git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。
在工作目录中修改某些文件。
将修改后的文件保存到暂存区域。
提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。
如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。
如果作了修改并已放入暂存区域,就属于已暂存状态。
如果是 Git 目录中保存着的特定版本文件,就属于已提交状态。
如果是还未纳入版本管理,就属于未跟踪状态。
Baidu一下,你就知道
Google一下,你就知道的太多了
```
mkdir gitlab-demo
cd gitlab-demo
git init
```
此方式用的不多,一般都采用克隆远程版本库的方式
克隆,顾名思义,远程版本库已存在
git clone [email protected]:wanglei/gitlab-demo.git
首先明确一下,所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
touch README.md
vi README.md
git add README.md
git commit -m "wrote a readme file"
选中待操作的文件或这个工程(注意文件颜色的变化)
Add to VCS
> ***一旦文件被Add to VCS,后续无需再Add: IDEA会在文件被修改后,自动进行Add***
git status
git log --pretty=oneline
git diff
git diff --cached
git diff HEAD
git diff HEAD -- GroupBean.java
当你改乱了工作区某个文件的内容,而且已经添加到了暂存区时,想丢弃修改:
git reset HEAD file
,对文件进行unstagegit checkout -- file
,文件回到与版本库一致的状态Note:
如果直接执行git checkout -- file
,则文件回到与暂存区一致的状态
当你改乱了工作区某个文件的内容,还未添加到暂存区时,想丢弃修改:
git checkout -- file
Note: IDEA会自动Add(stage)
通常需要先查看版本提交日志
可以通过从当前版本(HEAD)回退N个版本的方式进行版本回退
git reset --hard HEAD^
,回退一个版本git reset --hard HEAD^^
,回退两个版本git reset --hard HEAD~N
,回退N个版本也可以回退到指定版本(双向的)
git reset --hard 3628164
撤销回退:git log
无法获得被回退了的版本号,可通过git reflog
查看我们的操作历史,从中可以得到被回退的版本号信息
Note: 注意HEAD、master、origin master指针的变化
git rm file
& git commit -m "彻底删除file"
,从版本库和工作目录中同时删除file文件。git rm --cached file
& git commit -m "版本库中删除,工作目录中保留file"
,从暂存区删除file文件,从而实现版本库中删除,工作目录中保留的目的。rm file
,可以通过git checkout -- file
恢复Note: IDEA只支持本地工作目录和版本库同时删除
本地删除file,然后Commit Changes
版本库根目录下创建文件: .gitignore
```
target
.DS_Store
.idea
*.iml
```
几乎每一种版本控制系统都以某种形式支持分支。
使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作,开发完成后,再一次性合并到开发主线上。
在很多版本控制系统中,这是个昂贵的过程,常常需要创建一个源代码目录的完整副本,对大型项目来说会花费很长时间。
但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!
Git 的开发者都喜欢以这种方式来开展工作:
在master 分支中保留完全稳定的代码,即已经发布或即将发布的代码。
与此同时,他们还有一个名为develop分支 专门用于后续的开发,或仅用于稳定性测试。当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到master分支。
还有在工作中,将开发任务分解为各个功能或者模块,用topic分支(topic branch主题分支,有又称为feature branch特性分支),
Git默认只有一个分支,交主分支,即master分支。所有向master分支的提交可以串成一条时间线,如下:
创建分支:git checkout -b feature1
,相当于git branch feature1
和git checkout feature1
查看分支:git branch
,当前分支前面会标一个*
号
合并分支分四步:
1. 切换到目标分支,如将feature1分支合并到master分支:git checkout master
2. 执行合并:git merge feature1
3. 如果存在冲突,则需要先处理冲突,然后再进行commit
3. 合并完成后,就可以放心地删除本地feature1分支了:git branch -d dev
4. 如果存在远程feature1分支,也可以将其删除:git push origin :feature1
创建分支
查看和切换分支
在feature1分支上进行修改提交后,新的分支图如下
合并分支
开发新功能的过程中,如果需要及时解决线上的一个Bug,但是目前新开发的代码又不能提交,该怎么办?
git stash
git checkout master
git checkout -b issue-001
...
git add -A
git commit -m "fix bug 001"
git checkout dev
git stash list
git stash apply stash@{0}
git stash drop stash@{0}
Note:
git stash pop
恢复至最近一次stash,同时将该stash删除
团队开发中,为了方便的交换大家的代码,通常需要搭建一个Git服务器,团队所有人都可以7x24访问。
服务器上创建的版本库,我们称之为远程版本库,所有人将本地版本库的修改推送至远程版本库。
Git服务器需要提供用户注册、权限管理、版本库管理、代码预览、issue跟踪等功能,常见的Git服务器如下:
很简单,可以去GitHub练练手。
Note: 通过Clone方式创建的本地版本库,不需要此步骤。
git remote add origin [email protected]:wanglei/gitlab-demo.git
IDEA Git不支持add remote repository,需要在命令行中进行处理。
Note:通过Clone方式创建的本地版本库 无需指定-u参数、将本地分支与远程分支关联起来
git push -u origin master
若远程库是空的,第一次推送时需指定具体的分支:
当你的小伙伴已经向远程分支推送了他的提交,而碰巧你也对同样的文件作了修改,那么你再推送时会失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突。
那么此时你就需要将远程最新的提交抓取下来,然后再本地合并,解决冲突再提交。
将本地分支与远程分支关联起来
git branch --set-upstream dev origin/dev
抓取并合并最新提交,合并冲突
git pull
提交并推送远程
git commit -m "merge and fix xxx"
git push origin dev
通常,版本库的master分支只有少数人能够直接推送,其他人只能通过创建Feature分支、像Master分支提交Merge Request的方式来提交代码。
提交Merge Request时,可以指定受理人,受理人会收到相应的Merge Request邮件,然后进行处理:
git fetch origin
git log master..origin/feature1
git checkout master
git merge origin/feature1
###### 如果合并后测试有问题,则进行回退
git reset --hard HEAD^ 或 master@{1}
###### 推送远程
git push
Note:
Merge Changes
前最好对当前本地的修改进行commit或者stash。- Command Line环境下,如果本地存在未提交的变更,则无法进行后续的Merge操作。
- IDEA中,则提供了
Smart Merge
功能,原理就是自动帮你Stash
&UnStash
。- 也可以在Branch视图中,选择对应的Remote Branch,进行Merge操作。
选中要合并的分支,执行合并
合并完成后,推送远程
Note:
- 需要到Git服务器提供的Web界面进行Merge Request的发起和关闭。
- Merge Request可以保证代码Review
发送注册申请邮件给GitLab管理员,邮箱为[email protected],邮件正文给出注册使用的邮箱地址。
注册申请成功后,GitLab会将用户名、初始密码发送至你的注册邮箱。
首次登录GitLab时,会强制重置密码,修改密码后重新登录即完成注册。
GitLab支持Http和SSH两种传输协议:
与GitLab建立互信的步骤如下:
生成SSH密钥对
ssh-keygen -t rsa -C "你的注册邮箱",一路回车即可。
最终在~/.ssh/下会生成id_rsa、id_rsa.pub两个文件
将SSH公钥添加到 GitLab SSH Keys 中。(在User Profile中)
id_rsa.pub中存放的即为SSH公钥
修改/etc/hosts
115.28.91.188 gitlab.server
修改SSH默认端口
由于Docker Container无法Link到Host主机的22端口(SSH默认端口),所以这里GitLab使用的端口为10022。
但Git默认使用的端口即为22端口,所以需要设置在SSH GitLab时使用特定端口(这里为10022)
vi ~/.ssh/config,内容如下
Host gitlab.server
Port 10022
Host *
Port 22
测试
ssh -Tvvv [email protected]
当看到Welcome to GitLab, xxx
和Exit status 0
时表示SSH配置成功。
master 分支是随时可发布的。
开发新功能时,直接从 master 分支创建新分支,赋予合适的分支名(ie: new-category-list)。
本地直接向分支 commit 代码,阶段性的将代码 push 到远程 repo。
当分支开发完成需要被 merge、或需要代码评审等其他帮助时,提交一个 PR。
当分支代码被评审通过、且新功能被确认时,你可以将其 merge 回 master 分支。
一旦分支被 merge 回 master,立即进行发布操作。
下面具体介绍一下上述的每一步:
这是 GitHub Flow 中唯一的一条硬性规定。
master 分支永远是 stable 的,所有提交上去的代码都是测试通过的。
功能分支的命名一定要能够顾名思义,这样可以方便团队了解哪些功能正在开发中,而且当你中途去开发其他功能、还能帮你快速的找到之前的功能分支。
可以将功能分支与 master 分支进行 compare 操作,方便查询每个分支做了哪些改动。
还可以分别查看每个功能分支的 commit 记录、活跃度。
这样做有两个好处:
使用远程 Repo 作为备份,防止严重的代码丢失。
其他人通过 git fetch
命令就可以看到最近活跃的功能开发。如果发现一个功能迟迟没有 push,也许需要一些帮助。
PR 是大家参与开源项目的利器:fork 一个开源项目、提交修改、然后向开源项目维护者提交 PR。
PR 也可以是内部项目 Code Review 工具。PR 既可以用来申请 merge,也可以用来请求别人的帮助 或者 请求一次代码 review。
当功能分支代码通过测试之后,便可以向 master 分支提交一个 PR。
由于 master 分支是随时可发布的,所有 PR 只有经过 review 和 signoff 后才能 merge 回主分支。
一旦你的代码被 merge 回 master 分支,你需要立即发布,否则就可能会有其他功能分支被merge。因为别人都是不可靠的,你肯定不希望别人提交的代码破坏你的功能。
挺不错的插件,未激活版的功能也可以免费一直用下去。戳这里了解更多
如果使用的 JDK 版本 >= JDK8,那么可以开启 useJava8LocalDateTimeEct 选项。
methodNameGenerateSql 下的配置按需启用。
本文写于2016年06月22日,现在读起来仍能温故知新。
模块,又称构件,是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合体)。
很久很久以前,JSer把完成特定功能的代码放入独立的文件中,以此来实现“模块化”。
作为Netscape 10天就开发出来的玩具语言,它为JSer们提供了太多大展拳脚的机会。
function m1 () { //... }
function m2 () {
//...
}
文件作为模块组织单元
缺点
var module1 = new Object({
_count : 0,
m1 : function (){
//...
},
m2 : function (){
//...
}
});
Object作为模块组织单元
优点
缺点
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
立即执行函数表达式(IIFE)
优点
模块的基本写法(ES5)
IIFE是模块化的基础(ES5)
var module1 = (function (mod){
mod.m3 = function () {
//...
};
return mod;
})(module1);
扩展了module1模块
优点
缺点
var module1 = ( function (mod){
//...
return mod;
})(window.module1 || {});
优点:
var module1 = (function ($) {
//...
})(jQuery);
依赖模块通过参数传入
优点
函数声明 & 函数表达式
回调函数 & 模块化 & 闭包
大家都以同样的方式编写、加载模块,更易阅读和协作。
var x = 5;
var addX = function(value) {
return value + x;
};
module.exports.addX = addX;
var example = require('./demo.js');
// 6
console.log(example.addX(1));
优点
缺点
实现
define("module", ["dep1", "dep2"],
function(d1, d2) {
return someExportedValue;
}
);
require(["module", "../file"],
function(module, file) {
//
}
);
优点
缺点
实现
优点
缺点
实现
UMD规范类似于兼容 CommonJS 和 AMD 的语法糖
模块定义的跨平台解决方案
优点
缺点
实现
CSS
IMG
WebFonts
HTML / Template
......
Webpack 是一个模块打包器
根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源
借助 Babel 可以将 ES6 模块 编译成 CommonJS 和 AMD
Code Splitting(代码拆分)
Loaders(加载器/转换器)
Clever parsing(智能解析)
Plugin system(插件系统)
Efficient(高性能)
Express
webpack-dev-middleware
webpack-hot-middleware
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.dev.conf');
var app = express();
var compiler = webpack(config);
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath,
stats: {
colors: true,
chunks: false
}
});
var hotMiddleware = require('webpack-hot-middleware')(compiler);
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({action: 'reload'});
cb();
})
});
// serve webpack bundle output
app.use(devMiddleware);
// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware);
// serve pure static assets
app.use('/static', express.static('./static'));
var express = require('express');
var proxyMiddleware = require('http-proxy-middleware');
var app = express();
var proxyTable = {
// http://thx.github.io/RAP/index_zh.html
'/login': 'http://rap.taobao.org/mockjs/1986/'
};
// proxy api requests
Object.keys(proxyTable).forEach(function (context) {
var options = proxyTable[context];
if (typeof options === 'string') {
options = {target: options};
}
app.use(proxyMiddleware(context, options));
});
"There are only two hard things in Computer Science: cache invalidation and naming things."
除了可以指定具体的文件名以外,还可以使用一些占位符,包括:
name
hash
chunkhash
{
output: {
filename: "output.[hash].bundle.js",
chunkFilename: "[id].[hash].bundle.js"
}
}
{
output: {
filename: "output.[chunkhash].bundle.js",
chunkFilename: "[id].[chunkhash].bundle.js"
}
}
代码分隔,按需加载。
import main from '../../main.js';
import OrderQuery from '../../views/order/OrderQuery';
import OrderDetail from '../../views/order/OrderDetail';
// 定义路由规则
let routeMap = {
'/': {
name: 'orderQuery',
component: OrderQuery
},
'/order-detail': {
name: 'orderDetail',
// 异步加载会导致丢失Style.(未被抽取到common.css中,也不在当前的chunks bundle js中)
component: function (resolve) {
require(['../../views/order/OrderDetail'], resolve);
}
// component: OrderDetail
}
};
// 启动应用
main.startApp(routeMap);
plugins: [
// If 'chunks' option omitted then all entry chunks are selected
new CommonsChunkPlugin({name: 'commons'}),
// Mark meta.js as entry chunk instead commons.js.
new CommonsChunkPlugin({name: 'meta', chunks: ['commons']})
]
压缩和混淆代码,减小 Bundle 的大小,提高加载速度,节省流量。
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
// generate dist index.html with correct asset hash for each entry.
Object.keys(baseConfig.entry).forEach(function (name) {
var htmlConf = {
filename: '../'.concat(name).concat('.html'),
template: './src/index.html',
inject: true,
chunks: ['meta', 'commons', name],
chunksSortMode: function (a, b) {
var index = {'meta': 1, 'commons': 2};
index[name] = 3;
var ai = index[a.names[0]],
bi = index[b.names[0]];
return ai && bi ? ai - bi : -1;
},
minify: {
// more options: https://github.com/kangax/html-minifier#options-quick-reference
removeComments: true,
collapseWhitespace: true
}
};
baseConfig.plugins.push(new HtmlWebpackPlugin(htmlConf));
});
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.css$/,
loader: 'vue-style!css!px2rem?remUnit=75' // 将 px 批量转成 rem
},
{
test: /\.js$/,
loader: 'babel',
include: projectRoot,
exclude: /node_modules/
},
{
test: /\.html$/,
loader: 'vue-html'
},
{
test: /\.(png|jpg|gif|svg|woff2?|eot|ttf)(\?v=[0-9\.]+)?$/,
loader: 'url',
query: {
limit: 10000,
name: '[name].[ext]?[hash:7]'
}
}
]
保证尽可能多的用户都能正常访问网站。
渐进增强是保证基本内容能够正常展示的情况下,增强现代浏览器的用户体验。
优雅降级是保证老浏览器也能够正常展示网页内容,去除非必须的酷炫特效。
网页设计应该做到根据不同设备环境自动响应及调整。
不仅仅是关于屏幕分辨率自适应以及自动缩放图片等。
更是一种对于设计的全新思维模式:移动优先、向下兼容。
遵循移动优先原则,交互&设计应以移动端为主,PC则作为移动端的一个扩展。
适配不同终端有两个关键点:响应式布局、响应式内容(图片、多媒体)。
CSS Media Queries
viewport
Flex
屏幕尺寸和分辨率
屏幕的DPI/PPI
物理像素(Physical Pixel)
设备独立像素(Density-Independent Pixel)
设备像素比(Device Pixel Ratio)
位图像素(Bitmap Pixel)
一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个物理像素都有自己的颜色值和亮度值。
也叫密度无关像素、CSS 像素、逻辑像素。
一种Web编程上的概念,是一个抽象的单位。
在不同的设备中,CSS 中的 1px 所代表的物理像素可能是不同的。
设备像素比(简称dpr)定义了物理像素和设备独立像素的对应关系。
设备像素比 = 物理像素 / 设备独立像素 // 在某一方向上,x方向或者y方向
在javascript中,可以通过window.devicePixelRatio获取到当前设备的dpr。
位图像素是栅格图像(如:png, jpg, gif等)最小的数据单元。
每一个位图像素都包含着一些自身的显示信息(如:显示位置,颜色值,透明度等)。
设备宽高为375×667,可以理解为设备独立像素(或CSS像素)。
dpr为2,根据上面的计算公式,其物理像素就应该 ×2,为 750×1334。
在不同的屏幕上(普通屏幕 vs Retina屏幕),CSS像素所呈现的大小(物理尺寸)是一致的,不同的是1个CSS像素所对应的物理像素个数是不一致的。
理论上,1个位图像素对应于1个物理像素,图片才能得到完美清晰的展示。
假设在普通屏幕下完美展示,但是在Retina屏幕下就会出现位图像素点不够,从而导致图片模糊。
对于dpr=2的retina屏幕而言,1个位图像素对应于4个物理像素,由于单个位图像素不可以再进一步分割,所以只能就近取色,从而导致图片模糊。
对于图片高清问题,比较好的方案就是两倍图(@2x),如:200×300(CSS Pixel)img标签,就需要提供 400×600 的图片。
两倍图在普通屏幕下显示,一个物理像素点对应4个位图像素点。
它的取色也只能通过一定的算法来实现(显示结果就是一张只有原图像素总数四分之一,我们称这个过程叫做downsampling)
肉眼看上去虽然图片不会模糊,但是会觉得图片缺少一些锐利度,或者是有点色差(但还是可以接受的)。
- 对比度:明暗
- 锐利度:边缘
- 清晰度:模糊
100×100的图片,分别放在100×100,50×50,25×25的img容器中,在Retina屏幕下的显示效果:
爱字图,可以通过看文字"爱"来区分图片模糊还是清晰。
条形图,通过放大镜其实可以看出边界像素点取值的不同:
只需上传大图(@2x),小图交给图片服务器处理,页面只要负责拼接 URL 即可。
不同 dpr 下,加载不同尺寸的图片。
利用 CSS Media Queries 或 Javascript。
搭建图片服务器,通过url参数,控制图片质量,或将图片裁剪成不同的尺寸。
Q: Bootstrap 布局适配的原理?
目前比较流行的、也是助手采用的布局适配方案是使用相对单位 rem。
html {
font-size: 75px;
}
div {
width: 2rem;
}
div 的实际宽度 width = 75px * 2 (即 150px)
在前端开发之前,VD 会给我们一个psd文件,称之为视觉稿。
移动端开发中,为了做到页面高清的效果,视觉稿往往会遵循以下两点:
首先,选取一款手机的屏幕宽高作为基准(以前是iPhone4s的320×480,现在更多的是iPhone6的375×667)。
对于Retina屏幕(如dpr=2),为了达到高清效果,视觉稿的画布大小会是基准的2倍,也就是说像素点个数是原来的4倍(对iPhone6而言,原先的375×667,就会变成750×1334)。
现在你应该知道,对于dpr=2的手机,为什么画布大小×2,就可以解决高清的问题了。
思考:对于2倍大小的视觉稿,在具体的CSS编码中如何还原每一个区块的真实宽高(也就是布局问题)?
针对不同屏幕尺寸和dpr动态改变根节点html的font-size(基准值)。
document.documentElement.clientWidth * dpr / 10
乘以dpr,是因为页面有可能为了实现1px border页面会缩放(scale) 1/dpr 倍(如果没有,dpr=1)。
除以10,是为了取整,方便计算(理论上可以是任何值)
iPhone4/5: 320px * 2 / 10 = 64px
iPhone6/6s: 375px * 2 / 10 = 75px
CSS方式
动态改变根节点 html 的 font-size/*iPhone 4/5*/
@media screen and (min-width: 320px) {
html {
font-size: 64px !important; /*no*/
}
}
/*iPhone 6/6s*/
@media screen and (min-width: 375px) {
html {
font-size: 75px !important; /*no*/ 缺点:不够精确,但是够用。
}
}
/*iPhone 6p/6sp*/
@media screen and (min-width: 414px) {
html {
font-size: 124.2px !important; /*no*/
}
}
JS方式
动态改变根节点 html 的 font-sizelet docEl = document.documentElement;
let fontEl = document.createElement('style');
let dpr = window.devicePixelRatio || 1;
let rem = docEl.clientWidth * dpr / 10;
// 动态写入样式
fontEl.innerHTML = 'html{font-size:' + rem + 'px!important;}';
docEl.firstElementChild.appendChild(fontEl);
// 给js调用的,某一dpr下rem和px之间的转换函数
window.rem2px = function (r) { 精确计算rem基准值,但要加载一段 js
r = parseFloat(r);
return r * rem;
};
window.px2rem = function (p, base) {
let r = p / (base || 75);
return r.toFixed(6);
};
window.jspx = function (r) {
r = parseFloat(r / 75.0);
return r * rem;
};
CSS方式
和JS方式
如果仅使用JS方式
,那么页面在加载后可能会重新布局(relayout/reflow),产生抖动。
所以先通过CSS方式
,基本确定页面布局;然后再通过JS方式
精确计算后,页面进行微调。
基于 iPhone6s 的 750×1334 高清视觉稿中有一个宽高 750×300px 的 div。
由前面的公式可算出 iPhone6s 下 rem基准值 = 75px
width: 10rem; // rem基准值 = 75px
height: 4rem; // rem基准值 = 75px
由前面的公式可算出 iPhone4s 下 rem基准值 = 64px
width: 10rem; => width: 640px;
height: 4rem; => height: 256px;
利用 Webpack 的 px2rem-loader 实现 px2rem 的自动转换。
不需要人肉进行 px2rem 的转换
调整样式时更简单、直观
iPhone6s的物理像素是 750×1334
VD 视觉稿也是基于 iPhone6s的物理像素 750×1334
CSS 中使用的逻辑像素也是基于 750×1334
CSS像素 = 物理像素 / dpr
这意味着在高清屏上,目前的 CSS 使页面放大到了两倍,页面无法完全展示。
let docEl = document.documentElement;
let metaEl = document.querySelector('meta[name="viewport"]');
let dpr = window.devicePixelRatio || 1;
let scale = 1 / dpr;
// 设置viewport,进行缩放
metaEl.setAttribute('content',
'width=' + dpr * docEl.clientWidth + ',initial-scale=' + scale +
',maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
// 设置data-dpr属性,留作的css hack之用(如根据不同的 dpr 设置不同的 font-size)
docEl.setAttribute('data-dpr', dpr);
普通屏幕,页面不进行缩放;2倍高清屏时,页面缩放50%;3倍高清屏时。。。
思考:rem 方案先按物理像素进行设计,然后又进行页面缩放、适配 CSS像素,这么折腾到底为了什么?开发时直接按照 CSS像素进行页面布局不是也可以么?
在讨论字体是否需要缩放时,通常要考虑设计师的要求:
字体大小要统一,大屏显示更多的文字。
字体大小随着屏幕的大小进行相应的缩放。
font-size: 16px; /* no */
[data-dpr="2"] input {
font-size: 32px; /* no */
}
font-size: 32px;
前提
VD 按照 iPhone6s 的物理像素 750×1334px 进行设计,且视觉稿上 font-size 为32px。(左边进行了页面 scale,右边使用了 rem 方案适配)
左边
font-size = dpr * 16px,结合页面scale = 1 / dpr,这就保证了字体在所有屏幕上的大小均为16px(CSS 像素)。
右边
font-size = 32px / 75(rem基准值),这使得字体能够根据屏幕的分辨率进行等比缩放处理。
这大概是设计师最敏感,最关心的问题了。
上图中,对于一条1px宽的直线,它们在屏幕上的物理尺寸(灰色区域)的确是相同的,不同的其实是屏幕上最小的物理显示单元,即物理像素,所以对于一条直线,iphone5它能显示的最小宽度其实是图中的红线圈出来的灰色区域,用css来表示,理论上说是0.5px。
设计师想要的 Retina 下 1px边框,其实是1物理像素。对于CSS而言,相当于0.5px边框,这是 Retina下(dpr=2)下能显示的最小单位。
然而,无奈并不是所有手机浏览器都能识别border: 0.5px; ios7以下,android等其他系统里,0.5px会被当成为0px处理,那么如何实现这0.5px呢?
border: 1px solid #dcdcdc; // 跳过 px2rem 的处理
scale = 1 / dpr
CSS中仍然指定1px,但页面进行了
1/dpr
缩放,实际的物理像素仍是1px。
该特性最先由Apple引入,用于解决移动端的页面展示问题,后续被越来越多的厂商跟进。
http://www.quirksmode.org/mobile/viewports.html
http://www.quirksmode.org/mobile/viewports2.html
http://www.quirksmode.org/mobile/metaviewport
http://weizhifeng.net/viewports.html
http://weizhifeng.net/viewports2.html
https://segmentfault.com/a/1190000004403527
Original & Zoom Out & Zoom In
在进行缩放时,元素的 CSS 像素不变,只是它占据的物理像素变化了,例如:
CSS 像素为100×100px的元素,放大到200%时,其 CSS 像素仍为100×100px,但其占用的物理像素为 200×200px,缩小亦同理。
思考
有没有遇到过,手机浏览器访问网站时,出现页面显示不完整 或 全部显示但元素非常小、看不清楚的情况。(有没有思考过背后的原因和解决方法)
放大后(右图)
,window.innerWidth/Height 变小了,因为可放入这个浏览器窗口中的元素减少了。
用户向上滚动,然后放大(右图)
,浏览器保持相同的元素位于可见页面的顶部,window.pageYOffset 并没有真正的更改:被滚动出窗口的CSS像素的数量仍然(大概)是相同的。经实际验证,是有改变的!!
viewport的功能是用来约束
网站中最顶级包含块元素(containing block)<html>
的。
思考
假设页面上一个 div 具有 width: 10% 属性,现在这个 div 会随着浏览器窗口大小的调整而恰好的放大和收缩。但是这到底是如何工作的呢?
<body>
元素(并且你还没有给它设置过宽度),所以问题就变成了<body>
的宽度是哪个?<body>
元素和它的父元素<html>
一样宽。<html>
元素的宽度是多少?它的宽度和浏览器窗口宽度一样。这就是为什么拥有 width: 10% 属性的 div 会占据整个浏览器窗口的10%。所有web开发者都很直观的知道并且在使用这种技术。
<html>
元素的宽度是被 viewport 的宽度所限制的,<html>
元素使用viewport宽度的100%。
viewport 实际上等于浏览器窗口,它就是这么定义的。
viewport 不是一个 html 结构,所以你不能用 CSS 来改变它。
viewport 在桌面环境下只是拥有浏览器窗口的宽度和高度,在移动环境下它会有一些复杂。
思考
对这个 div 进行缩放会是什么效果?
document.documentElement
实际上指的是<html>
元素,viewport 要比它更高一层,它是包含<html>
元素的元素。
如果你给<html>元素设置width属性(如右图)
,document.documentElement.clientWidth/Height 给出的仍然是viewport的尺寸,,而不是<html>
元素的。
document.documentElement.clientWidth/Height
不包含滚动条。
window.innerWidth/Height
包含滚动条。
事实上两个属性对的存在是浏览器战争的产物。最初Netscape只支持 inner、IE 只支持 client,后来所有其他浏览器都开始支持 client,但是 IE 却没有支持 inner。
在 PC 上拥有这两个属性对是有一些累赘的,BUT,就像我们将要看到的,在移动端这将会得到祝福。
<html>
元素<html>
)的尺寸。
pageX/Y
提供了相对于<html>
元素的以CSS像素
度量的坐标。
clientX/Y
提供了相对于viewport
的以CSS像素
度量的坐标。
screenX/Y
提供了相对于屏幕
的以物理像素
进行度量的坐标。
90%
的时间你将会使用pageX/Y
,其他的10%
时间你将会使用clientX/Y
,但你永远不需要知道事件相对于屏幕的坐标。
你可以声明「只在页面宽度大于,等于或者小于一个特定尺寸的时候才会被执行」的特殊的CSS规则。
div.sidebar {
width: 300px;
}
@media screen and (max-width: 400px) {
// styles assigned when width is smaller than 400px
div.sidebar {
width: 100px;
}
}
width/height
使用 viewport 宽高(CSS 像素)。
* `device-width/device-height`使用屏幕宽高(物理像素)。
* 在桌面环境下去使用`width`而去忘记`device-width`吧。
* IE 浏览器不支持媒体查询。
屏幕尺寸小,为 PC 设计的网站在移动浏览器中显示的内容明显要少。
对网页进行缩放直到文字小得无法阅读。
以合适的尺寸只显示网页中的一小部分内容。
viewport 太窄,以至于不能正常展示你的 CSS 布局(不管是固定宽度、百分比 或 流式布局)。
明显的解决方案是使 viewport 变宽一些,这样就产生了两个视口:
George Cummins在Stack Overflow上给出了最佳解释:
把
layout viewport 想像成为一张不会改变大小和形状的大图。
现
在想像你有一个小一些的框子,你通过它来看这张大图。(可以理解为「管中窥豹」),这个小框子的周围被不透明的材料所包围,遮挡住了你的视线,你只能看到这张大图的一部分。
你
通过这个框子所能看到的大图的部分就是 visual viewport。
通
过远离(缩小)/ 靠近(放大)这种方式,你可以调整所能看大图的内容多少,但是大图(layout viewport)的大小和形状永远不会变。
?
)。由于宽度趋近,CSS 只需要像在 PC 上那样渲染页面就行,原有的页面结构不会被破坏。
visual viewport 是页面当前显示在屏幕上的部分,可以简单的认为是手持设备物理屏幕的可视区域。
可以通过滚动来改变所看到的页面的部分,或者通过缩放来改变 visual viewport 的大小。
无论怎样,CSS 布局,尤其是百分比宽度,是以 layout viewport 做为参照系来计算的,它被认为要比 visual viewport 宽。
很显然两个 viewport 都是以 CSS 像素度量的。
但是当进行缩放(如果你放大,屏幕上的 CSS 像素会变少)的时候,visual viewport
的尺寸会发生变化,layout viewport
的尺寸仍然跟之前的一样。
如果不是这样,缩放时
layout viewport
尺寸发生变化,那你的页面将会像百分比宽度被重新计算一样而经常被重新布局。
以完全缩小的模式来展示任何页面
,此时 visual viewport = layout viewport。完全缩小模式下
旋转手机至横屏时,visual viewport 会发生变化,但浏览器通过轻微的放大来适配这个新的朝向,所以 layout viewport 又和 visual viewport 一样宽了。
这对 layout viewport 的高度会有影响,现在的高度比肖像模式(竖屏)要小。但是web开发者不在乎高度,只在乎宽度。
朝向会对高度产生影响,但对宽度不会产生影响。
<html>
元素<html>
元素的整个尺寸,完全支持 iPhone 和 Android。pageX/Y
仍然是相对于页面,以 CSS 像素为单位。
clientX/Y
是相对于visual viewport来计算,以CSS像素为单位。
screenX/Y
是相对于屏幕来计算,以物理像素为单位。(这和clientX/Y用的参照系是一样的)
媒体查询和其在 PC 上的工作方式一样。
width/height 使用 layout viewport做为参照物,并且以 CSS像素进行度量。
device-width/height 使用设备屏幕,以设备物理像素进行度量。
<head>
下的 <meta>
标签html {width: 320px}
,现在<html>
元素收缩了,并且其他元素现在使用的是 320px 的 100%。这在用户进行放大操作的时候有用(无需左右滑动),但是在初始状态是没用的,你什么都看不清。为了绕开这个问题(初始状态无效、需要手动放大
)苹果发明了viewport meta标签。
当你设置的时候,你就设置了 layout viewport 的宽度为320px。现在页面的初始状态也是正确的:
width
设置layout viewport 的宽度,正整数或"width-device"。
initial-scale
设置页面的初始缩放值,数字且可带小数。
minimum-scale
允许用户缩放的最小倍数值,数字且可带小数。
maximum-scale
允许用户缩放的最大倍数值,数字且可带小数。
height
设置 layout viewport 的高度,但并不被支持。
user-scalable
是否允许用户进行缩放,值为"no"或"yes"。
比如:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
device-width
将 layout viewport 设置为屏幕的宽度,单位是 CSS 像素。
在指定了initial-scale=1.0
时,可省略width=device-width
BAD
JSP 里揉杂大量Java业务代码,代码的可维护性差。
BAD
前后端没有合理分工。
代码可维护性得到明显好转,MVC 是个非常好的协作模式,从架构层面让开发者懂得什么代码应该写在什么地方。
为了让 View 层更简单干脆,可以选择 Velocity、Freemaker 等模板,使得模板里写不了 Java 代码,前后端分工更清晰。
BAD
前端开发重度依赖开发环境。
BAD
前后端职责依旧纠缠不清。
2004 年 Gmail 像风一样的女子来到人间,很快 2005 年 Ajax 正式提出,加上 CDN 开始大量用于静态资源存储,于是出现了 JavaScript 王者归来的 SPA (Single Page Application 单页面应用)时代。
前后端的分工非常清晰,前后端的关键协作点是 Ajax 接口。
复杂度从服务端的 JSP 里移到了浏览器的 JavaScript,浏览器端变得很复杂。
类似 Spring MVC,这个时代开始出现浏览器端的分层架构,如 Backbone。
不足
前后端接口的约定。
不足
前端开发的复杂度控制。
Backbone的Model把服务器端的数据模型映射到浏览器端,绑定数据验证机制,并与相应的REST操作绑定。
Backbone的Model没有与UI视图数据绑定,而是需要在JS中自行操作DOM来更新或读取UI数据。
前后端分工很清晰,可以让开发并行,测试数据的模拟不难,前端可以本地开发,后端则可以专注于业务逻辑的处理。
前端开发的复杂度可控,前端代码很重,但合理的分层(比如Templates、Controllers、Models等),让前端代码能各司其职。
后端一套Server API,多端使用(Web、移动APP等)
部署相对独立,产品体验可以快速改进。
不足
代码不能复用。
不足
全异步,对SEO(搜索引擎优化)不利,往往还需要服务端做同步渲染的降级方案。
不足
性能并非最佳,特别是移动互联网环境下。
不足
SPA 不能满足所有需求,依旧存在大量多页面应用。URL Design 需要后端配合,前端无法完全掌控。Bigpipe:
挑战
前端需要对服务端编程有更进一步的认识,比如 network/tcp等知识的掌握。挑战
架构上多了一层 Node,提升了系统的复杂度和风险,也肯定会有一定的性能损耗。由此带来的损失,一定要从其他方面弥补回来。
挑战
对部署、运维层面的熟练了解,需要更多知识点和实操经验,无法一蹴而就。挑战
大量历史遗留问题如何过渡,这可能是最大的阻力。(如何把一个已有的项目,过渡为这种模式?)一些软件设计的原则:http://coolshell.cn/articles/4535.html
为什么需要前后端分离?
前后端分离为什么需要 Node ?
Content
Server
Cookie
CSS
JavaScript
Images
减少 http 请求数
DNS系统是从域名到 IP 地址映射系统,DNS 解析一次大约20-120毫秒,在这个时间内浏览器不能下载任何东西。
减少 DNS 解析时间
避免使用重定向
使用重定向会降低用户体验,它会使加载延时。
缓存 ajax
延迟/提前 加载模块
Post-load
只加载当前页面需要的模块资源,以最快的速度展现当前页面,提升用户体验。Preload
利用浏览器的空闲时间,加载下一页面将要需要的模块资源,这样下一页面将更快速的展现给用户。减少dom的element数量
查看dom的元素数document.getElementsByTagName('*').length
把资源分散到多个域名下
把资源分散到多个域名下可以尽量多的并行下载,但是不要超过2-4个域名,因为 DNS 解析会也有一定的损耗。
避免404
使用 CDN 内容分发网络系统
Cache-Control:
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn#cache-control
为http头添加Expires或Cache-Control
使用 Gzip 传输部件
Ajax 请求使用 Get 方法
避免 src 为空的 Image 元素
减小 Cookie 长度
客户端在跟服务端通信时,会带上Cookie信息,所以减小 Cookie 长度,可以一定程度的降低响应时间。
把静态资源放在无 Cookie 的域名上
把 css 放在 head 里
避免在 css 中使用 js 表达式
Background-color:expression((new Date).getHours()%2?'#000':'#fff');
网页渲染 或者 窗口缩放 时 expression 会被重新计算。
页面滚动 或者 鼠标移动 时都会重新计算。
加载 css 时,要用 link,不要用 @import
在 IE 上用 @import 的作用与把 放入网页底部的作用是一样的,所以不要使用。
把 js 放在底部
如果一个 js 脚本可以被推迟加载,那就把它放到页面最下面吧,这样会让你的页面以最快的速度展现给用户。
把 js 和 css 放入外部文件
最少化(压缩) js/css 源码
去除重复的 js 脚本
减少 DOM 查询
优化图片 - 无损压缩
优化雪碧图
不要在html里缩放图片
当你需要100×100的图片时,不要使用500×500的图片进行缩放,直接提供一张100×100图片就好。
让 favicon.ico 小一点儿(1K以下),并且可缓存(缓存几个月)
Git Flow 分支模型约定了 5 种分支,模型比较复杂。需要团队中每个人都能正确地理解和选择正确的分支进行工作,对整个团队的纪律性提出了很高的要求。
规则越复杂,应用起来就越难,导致很多团队不得不借助额外的 Git 扩展脚本 gitflow 去应用这一套复杂的规则。
Feature 分支有一下两个明显的好处:
同时 Feature 分支也带来如下两个问题:
Feature 分支在较长周期的开发完成后才能 merge 回 develop 分支,而在此期间 develop 分支可能已经被其他 Feature 分支修改过。
即使其他 Feature 分支进行过 rename 这种非常简单的重构,merge 时也需要处理大量的冲突。
Feature 分支降低了代码集成的频率,big bang conflict 总是无法避免。
原则上要求各 Feature 分支的负责人将代码 merge 回 develop 分支,发现冲突、即刻解决。但一旦持续集成时、发现代码运行状态异常,该由哪个 Feature 负责人去解决问题?
Feature 分支的问题归根结底是 代码隔离
和 持续集成
的矛盾。
Hotfix、Release 甚至 Feature 分支都有可能需要自己的持续集成环境,这是需要额外的硬件资源和虚拟化能力的,对小团队都是个很大的挑战。
版本格式:主版本号.次版本号.修订号
版本号递增规则如下:
主版本号:当你做了不兼容的 API 修改
次版本号:当你做了向下兼容的功能性新增
修订号:当你做了向下兼容的问题修正
先行版本号及版本编译信息可以加到**“主版本号.次版本号.修订号”**的后面,作为延伸。
这套版本系统被称为 语义化的版本控制
主版本号为零(0.yz)的软件处于开发初始阶段,一切都可能随时被改变。这样的公共API 不应该被视为稳定版。
每当次版本号递增时,修订号 “必须MUST” 归零。
每当主版本号递增时,次版本号和修订号 “必须MUST” 归零。
被标上先行版本号则表示这个版本并非稳定而且可能无法达到兼容的需求。范例:1.0.0-alpha、1.0.0-alpha.1、 1.0.0-0.3.7、1.0.0-x.7.z.92。
版本编译信息 “可以MAY” 被标注在修订版或先行版本号之后,先加上一个加号再加上一连串以句点分隔的标识符号来修饰。范例:1.0.0-alpha+001、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。
版本的优先层级指的是不同版本在排序时如何比较。范例:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0- rc.1 < 1.0.0。
代码要有代码的规范,协作要有协作的规范,Commit Message 也可以有自己的参考规范。
前端 JS 框架 Angular:
前端知名 JS 框架 MingGeJS
想想我们自己的 Commit Message,更像哪一个?
接下来我们来分析下 Angular 的 Commit Message!
<type>(<scope>): <subject>
<空行>
<body>
<空行>
<footer>
分成标题、内容详情、结尾三个部分,各有各的用处,没有多余项。
标题是可以直接在页面中预览的部分,分为 type、scope、subject 三部分。
type
scope
用来说明本次 Commit 影响的范围,即简要说明修改会涉及的部分。
subject
用来简要描述本次改动,概述就好了,因为后面还会在 body 里给出具体信息。但最好遵循下面三条:
是对上面 subject 里内容的展开,在此做更加详尽的描述,内容里应该包含修改动机和修改前后的对比。
主要放置 不兼容变更 和 Issue 关闭的信息。
如果是撤销之前的 Commit,那么本次 Commit Message 必须以 revert:开头。
body 中必须要记录所撤销的 Commit 的 SHA 值。
相对固定的发布周期/迭代周期
做好项目的版本计划
如果没有规律的迭代周期和可靠的版本计划,即使我们的 Git 分支模型再强大,开发团队也免不了焦头烂额。
master:受保护分支,不允许开发人员直接 commit,且随时可发布生产环境。
develop:只有本迭代相关代码、在开发完成以后才能通过以提交 PR 的形式、申请 merge 回 develop 分支。develop 分支用于发布测试环境。
feature:一旦初始版本上线以后,所有功能开发必须在 feature 分支上进行开发,用完即删,包括对应的远程分支。
hotfix:如果线上发现严重 Bug、需要紧急修复,这时从 master 分支检出 hotfix 分支、进行 Bug 修复工作。
$ git checkout master
$ git tag -a 1.0.0
$ git checkout -b develop master
假设有4个新功能需要开发:
开发个人
从 develop 分支创建 Feature 分支进行开发:
$ git checkout -b feature-f1 develop
$ git checkout -b feature-f2 develop
$ git checkout -b feature-ff3 develop
$ git checkout -b feature-uf4 develop
开发个人
切换至本地 develop 分支,pull 最新代码:
$ git checkout develop
$ git pull
开发个人
切换至相关 Feature 分支,merge develop 分支的最新代码:
$ git checkout feature-f1
$ git merge --no-ff develop
merge 完成、自测通过后,开发个人
向 develop 分支发起一个 PR/MR 请求,申请 Code Review,指定相关人员。
在收到 PR/MR 后,相关人员
需要及时完成 Code Review,如有问题需要开发个人
进行相关调整。
确认无误后(代码 OK、版本计划没有变动),相关人员
接受 PR/MR、将 feature-f1 merge 回 develop 分支。
signoff 需要在 PR/MR 在对话列表中体现,作为 Code Review 的凭证。(由于 develop 不是保护分支,在接收到 signoff 后,也可以由开发个人
自行接受 PR/MR、完成 merge)
merge 完成后,通知测试人员
feature-f1功能已实现、可以发布测试环境,最终由测试人员
决定何时发布测试。
TODO:结合 GitHooks 自动触发 Jenkins 发布测试环境
开发个人
从 master 分支检出 Hotfix 分支:
$ git checkout master
$ git pull
$ git checkout -b hotfix-0022
必要时需要为 Hotfix 分支提供独立的持续集成环境(CI 任务、主机、Web 容器、数据库实例等)。
Bug 修复成功后,开发个人
向 master 和 develop 分支发起 PR/MR 请求代码合并,同时指定相关人员。
相关人员
完成 PR/MR 的处理,将修复代码 merge 回 master 和 develop 分支,通知发布人员
发布生产。
发布生产以后,通知相关人员开始必要的验证工作。
相关人员
将 develop 代码 merge 回 master 分支,通知发布人员发布生产:
$ git checkout develop
$ git pull
$ git checkout master
$ git merge --no-ff develop
$ ./bump-version.sh 1.2.0
version bumped to 1.2.0
$ git tag -a 1.2.0
TODO:结合 GitHooks 自动触发 Jenkins 发布生产环境
必要时,需要为跨迭代的 Feature 分支提供独立的持续集成环境。
......
本文写于2016年08月15日
国人作者,官方提供详尽的中文文档。
部分相关类库也提供了中文文档。
[slide]
概念少,API 简单,容易上手。
vue-cli,一分钟搞定 webpack 配置。
Model 就是普通的 JavaScript 对象。
官方提供了全套方案(组件、路由和状态)
Webstorm/Sublime/Atom Plugins
[slide]
[slide]
Name | Desc | Link |
---|---|---|
VueStrap | 基于 Bootstrap 的一套组件* | vue-strap |
VueBoot | 基于 Bootstrap 的一套组件 | vue-boot |
VueAdmin | 用于控制台面板开发的一套组件* | vue-admin |
Keen-UI | MD 风格的一套组件* | keen-ui |
Vue-Bulma | 基于 Bulma 的一套组件* | vue-bulma |
Vue-Comps | 一套未 styled 的组件* | vue-comps |
[slide]
[slide]
官方提供路由类库 Vue-Router
var Foo = Vue.extend({
template:
'<div class="foo">' +
'<h2>This is Foo!</h2>' +
'<router-view>' +
'</router-view>' +
'</div>'
})
</code></pre>
<pre><code class="javascript">
router.map({
'/foo': {
component: Foo,
subRoutes: {
'/bar': {
component: Bar
},
'/baz': {
component: Baz
}
}
}
})
</code></pre>
[slide]
State Management
官方提供状态管理类库 Vuex
import Vuex from 'vuex'
const state = {
count: 0
}
const mutations = {
INCREMENT (state) {
state.count++
}
}
export default new Vuex.Store({
state,
mutations
})
</code></pre>
<pre><code class="javascript">
store.dispatch('INCREMENT')
console.log(store.state.count) // -> 1
</code></pre>
[slide]
[slide]
Supported Browsers
Vue.js supports all ECMAScript 5 compliant browsers.
[slide]
Community
[slide]
Performance
-
Vue.js 更轻量,~24kb min+gzip。
-
由于 React 的虚拟 Dom 的实现,它的 scripting 上运行的时间更长;Vue 由于要直接更改 Dom ,所以它有关在 painting 和 rendering 工作上更耗费资源。
-
所有工作都做完以后,Vue 在大多数情况下仍然比 React 快25%。
[slide]
TODO
Third Party Integration
- JQuery
- amChart
FAQ
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.