Azure SQL包括
ESLint
安装并初始化既有项目
1 | npm eslint --init |
安装后自动运行cli提示,选择所需的运行环境(node.js vs browser),模块化风格(es import/export vs CommonJS),是否使用typescript等
之后会向package.json添加并安装@typescript-eslint/eslint-plugin eslint-plugin-react @typescript-eslint/parser eslint等
配置cli(commandline interface)
package.json1
"lint": "eslint --ext .js src/"
Issue: ‘global’ is not defined
对于使用webpack打包的web app其编译环境是node.js的,因此可以配置
1
2
3
4 "env": {
"browser": true,
"node": true
},
ESLint:环境参数
Issues:
Arrow function expected no return value. (consistent-return)
141:7 error React Hook useEffect has a missing dependency: ‘render’. Either include it or remove the dependency array react-hooks/exhaustive-deps
render 方法中包含state属性 应改为useCallback 加入依赖state属性, 然后把render加入报错的副作用的依赖中
Expected ‘this’ to be used by class method ‘getValBetweenFms’. (class-methods-use-this)
改为static方法
Expected to return a value at the end of method ‘getValBetweenFms’. (consistent-return)
函数在循环体中某条件达成时返回 运行时必定返回 但静态类型检查不通过 应在函数末尾return undefined
Kubernetes
Kubernetes 也称为 K8s,是用于自动部署、扩缩和管理容器化应用程序的开源系统。
Angular工作空间配置
工作区配置文件就是angular.json
关于当前Project
1 | "MyApp": { |
编译/测试等工具
关于build target
architect/build 节会为 ng build 命令的选项配置默认值。它具有下列顶层属性:builder,option,configurations.
另外对应ng serve,ng test,ng lint命令,有architect/serve|test|lint命令
- builder就是个编译器名字,默认是@angular-devkit/build-angular:browser,(ng test的是karma,ng lint的是tslint)
- options提供构建时的选项及默认值,私以为这些option可以认为是builder工具链所需参数,因而在test和lint中也各有不同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24"options": {
"aot": true,
"progress": false,
"extractCss": true,
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
}
],
"styles": [
"src/theme.less",
"src/styles.scss"
],
"scripts": []
} - configurations 脚手架生成项目会添加一个production的配置在这里,对编译进行部分优化以及打包限制,ng build 带—prod参数(注意—xxx是命令参数)使用该production配置,可以仿照production写其他(如 stage)配置,使用时形如 ng build —configuration stage
另配置可以加载复数个,后者的项会覆盖前者:ng build —configuraion staging,fr
“configurations”: {
“production”: {
}"fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "budgets": [ { "type": "initial", "maximumWarning": "2mb", "maximumError": "5mb" }, { "type": "anyComponentStyle", "maximumWarning": "6kb", "maximumError": "10kb" } ]
}
```样式预处理选项
Angular Doc:Styles and scripts configuration
Angular-Tips
ngFor loop with async pipe
参数订阅可观察对象的值,从而保持最新,当数据更新时,循环渲染的视图会随之更新,见StackOverflow:*ngFor loop with async pipe?
完整栗子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21@Component({
selector: 'users-list',
template: `
<ul>
<li *ngFor="let user of users$ | async">
{{ user.username }}
</li>
</ul>
`
})
export class UsersListComponent {
users$;
constructor(private http: Http) { }
ngOnInit() {
this.users$ = this.http
.get('/api/users')
.map(res => res.json());
}
}
如果需要基于返回值的其他参数,有1
*ngFor="let user of users$ | async as users; index as i"
这里的users就是Array类型了
类似的ngIf也可以用异步管道,形如*ngIf=”user$ | async as user”,显然这里的user$应为Observable\
ngIf else
1 | <div *ngIf="isLoggedIn(); else notLoggedIn"> |
事件‘委托’
需求是文件上传,往往隐藏input type=”file”而放一个好看的入口。
事件可以直接在HTML的native element上触发,在jQuery中1
$("#fileInput").click();
原生js1
document.getElementById("fileInput").click();
Angular可以使用viewChild获取元素1
2
3
4
5
6
7
8@ViewChild('fileInput') fileInput:ElementRef;
constructor(private renderer:Renderer) {}
showImageBrowseDlg() {
let event = new MouseEvent('click', {bubbles: true});
this.renderer.invokeElementMethod(
this.fileInput.nativeElement, 'dispatchEvent', [event]);
}
MDN:dispatchEvent
通过dom结构定位元素1
2
3
4
5
6
7
8
9
10
11
12
13
14<div style="width: 128px; height: 128px; background-color: #fafafa;
border: 1px dashed #d9d9d9;
border-radius: 2px;cursor: pointer;display: flex;justify-content: center;align-items: center;"
(click)="showImageBrowseDlg($event)"> +
<input type="file" style="display: none;" (change)="handleUpload($event)">
</div>
showImageBrowseDlg(event){
if(event.target.children[0]){
const fileinput:HTMLElement = event.target.children[0] as HTMLElement;
fileinput.click();
event.stopPropagation();
}
}
Angular-SPECS
封装一个http的provider,参考ionic3+angular4 HttpClient封装优化
Jasmine
测试驱动开发(Test Driven Development, TDD)和行为驱动开发(Behavior Driven Development, BDD)
Jasmine 通过用自然语言书写非程序员可读的测试用例扩展了测试驱动开发方法, 行为驱动开发人员使用混合了领域中统一的语言的母语语言来描述他们的代码的目的
被测系统(System under test, SUT)
单测不负责检查跨类或者跨系统的交互逻辑,那都是集成测试的范围
单测不能受到外界环境的影响, 依赖需要用本地实现注入,或者提供一个mock(桩对象)
单测需要能快速执行,有必要在每次修改代码时运行单测
单测应随编码进行,补单测是没有意义的
1 | ├───lib |
spec + src文件夹是栗子
笔记目的导向:
- spec.ts写的啥(Jasmine 单元测试的书写语法)
- 组件声明周期中应该存在哪些用例(如实例化,输入/输出,方法,释放)
- 依赖项的处理init with Node.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58describe("Player", function() {
var player;
var song;
beforeEach(function() {
player = new Player();
song = new Song();
});
it("should be able to play a Song", function() {
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
//demonstrates use of custom matcher
expect(player).toBePlaying(song);
});
describe("when song has been paused", function() {
beforeEach(function() {
player.play(song);
player.pause();
});
it("should indicate that the song is currently paused", function() {
expect(player.isPlaying).toBeFalsy();
// demonstrates use of 'not' with a custom matcher
expect(player).not.toBePlaying(song);
});
it("should be possible to resume", function() {
player.resume();
expect(player.isPlaying).toBeTruthy();
expect(player.currentlyPlayingSong).toEqual(song);
});
});
// demonstrates use of spies to intercept and test method calls
it("tells the current song if the user has made it a favorite", function() {
spyOn(song, 'persistFavoriteStatus');
player.play(song);
player.makeFavorite();
expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
});
//demonstrates use of expected exceptions
describe("#resume", function() {
it("should throw an exception if song is already playing", function() {
player.play(song);
expect(function() {
player.resume();
}).toThrowError("song is already playing");
});
});
});1
2npm install --save-dev jasmine
npx jasmine initdescribe
以describe分组specs,它代表一组相似的测试用例,通常有 2 个参数:字符串和方法。字符串作为特定 Suite 的名字和标题。方法是包含实现的代码。1
2
3
4
5
6describe ('HeroesService (with spies)', () => {
...
});
describe('HeroesService (with mocks)', () => {
...
});waitForAsync TestBed
1
2
3
4
5
6
7
8
9
10
11
12
13
14import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing';
describe('nz-table', () => {
let injector: Injector;
beforeEach(
waitForAsync(() => { //
injector = TestBed.configureTestingModule({
imports: [BidiModule, NzTableModule],
declarations: [NzTestTableBasicComponent, NzTestTableScrollComponent, NzTableSpecCrashComponent, NzTestTableRtlComponent]
});
TestBed.compileComponents();
})
);
...
})it 和 specs
specs即specification(规则),它们是一个个断言,可以是 true 或者 false。当每个 Spec 中的所有 expectations 都是 true,则通过测试。以it函数定义,与describe类似的,有 2 个参数:标题和方法。expect tobe
1
2expect(true).toBe(true);
expect(false).not.toBe(true);断言
- toBe 和 toEqual 前者相当于比较运算符=== 后者比较字面量的值(对于对象进行属性的比较)
- toMatch
- toBeDefined 和 toBeNull
- toContain
- toBeGreaterThan 和 toBeLessThan
- toBeCloseTo
- toThrow
beforeEach和afterEach
分别在每个it断言测试前/后调用spy
存根(stub)和跟踪(track)任意函数spy一个foo对象上的setBar方法,分别断言该方法被调用、被调用若干次、被以某某参数调用1
2
3
4
5
6
7
8
9
10
11
12
13
14spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("tracks that the spy was called", function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("tracks that the spy was called x times", function() {
expect(foo.setBar).toHaveBeenCalledTimes(2);
});
it("tracks all the arguments of its calls", function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
});
很多时候用spy对应模拟对象
用例
DevOps-Overview
DevOps 是人员、流程和产品的集合体现,它可让我们向最终用户持续交付价值。 ———— Donovan Brown
Azure DevOps
Azure DevOps 是 Microsoft 提供的一种软件即服务 (SaaS) 平台,它能提供用于开发和部署软件的端到端 DevOps 工具链。
组成
- Azure Repos 源代码管理
- Azure Pipelines CI/CD服务
- Azure Boards 类似TP的kanban工具以及Agile tools等
- Azure Test Plans 测试工具,包括manual/exploratory testing 和 continuous testing
- Azure Artifacts 大致上就是构建自己的库(allows teams to share packages such as Maven, npm, NuGet and more from public and private sources and integrate package sharing into your CI/CD pipelines)
生产DevOps的内容
- 操作系统
- 脚本
- 容器
- 云
- 其他
琐碎
staging vs deployment slot
它们是两个不同层面、维度的概念,但它们经常被结合使用,以实现高效的软件发布流程。
staging环境介于开发和生产之间的独立、隔离的运行环境。用于模拟生产环境以发现问题。deployment slot是云平台提供的 可运行同一个应用的多个版本(比如生产版和暂存版)
亦可做蓝绿部署和版本回退
DevOps之基于Release的工作流
对于branch
对于敏捷开发的团队,选择避免使用长期分支(long-lived branch),以致力于短期功能和 Bug 修复分支,任何工作付出的目标都是以生成pull request将工作合并回master
A long-lived branch is a Git branch that is never deleted. Some teams prefer to avoid them altogether in favor of short-lived feature and bug fix branches. For those teams, the goal of any effort is to produce a pull request that merges their work back into master.
对于web应用,往往不会支持或回退到起初的版本,适用于上述工作方式,但也有其他场景需要长期保留分支,如用于同时支持市场上的多个版本,release V1, release V2将持续维护
master是稳定版分支,与线上版本保持绝对一致,release是预发布分支,从develop创建出来进行测试。
关于release
语义化版本标签
release notes(存目)
Azure 网络管理
配置和管理虚拟网络占比30-35%
目标导向:
- 学习创建虚拟网络
- 创建虚拟VPN网关
- 认识使用ExpressRouter
虚拟网络
功能: - 隔离和分割(Isolation & segmentation)
- 网络通信、资源间通信、与本地网络(on-premises)通信
- 连接虚拟网络
- 路由|筛选|连接网络流量(route|filter network traffic)
VPN(virtual private networks):
- Point-to-site
- Site-to-site
- Azure ExpressRoute
Network Monitor
- 监视vm与endpoint(可以是其他vm)之间的通信
- 查看vnet中的资源及其关系
- 诊断(Diagnose)出入vm的网络流量筛选问题
- 诊断vm网络路由问题
- 诊断vm出站连接(outbound connections)
- 捕获出入vm的数据包
- 诊断vnet网关与连接的问题
- 检查区域与internet相对延迟
- 查看安全规则
概念
IP地址空间:举个栗子地址空间192.168.1.0/24,子网掩码255.255.255.248。子网掩码用来指明某个IP地址哪些位是网络位,哪些是主机位,同网络位IP之间的通信不需要通过网关,主机位数值就是有多少主机。IP总共32位,‘/24’是指前24位都是网络位,主机坐在的网络,248即11111000,这个网络有可以有 25 即32个子网,每个子网可分配地址为 23 - 2(减去广播地址和网络地址),为6个虚拟机通过虚拟网络通信的实践
创建虚拟网络,名为default使用powershell创建两个Azure VM1
2$Subnet=New-AzVirtualNetworkSubnetConfig -Name default -AddressPrefix 10.0.0.0/24
New-AzVirtualNetwork -Name myVnet -ResourceGroupName vm-networks -Location $Location -AddressPrefix 10.0.0.0/16 -Subnet $Subnet*取消其中一台的公共IP1
2
3
4
5
6
7New-AzVm `
-ResourceGroupName "vm-networks" `
-Name "testvm1" `
-VirtualNetworkName "myVnet" `
-SubnetName "default" `
-image "Win2016Datacenter" `
-Size "Standard_DS2_v2"使用PublicIP远程VM1,在VM1使用计算机名访问同一虚拟网络的VM21
2
3$nic = Get-AzNetworkInterface -Name testvm2 -ResourceGroup vm-networks
$nic.IpConfigurations.publicipaddress.id = $null
Set-AzNetworkInterface -NetworkInterface $nic
VPN网关
Azure虚拟网关为‘从本地到Azure’的传入连接提供一个endpoint,VPN网关是一种虚拟网关类型,可以作为加密的endpoint,在Azure的实践中,VPN网关用以在不同区域之间安全地链接虚拟机和服务