OctoPer的負載測試IDE(kraken)是具備多個前端應用程序的angular項目,javascript
這篇博文是想給每一個想要建立具備多個應用程序和庫的Angular Workspace的開發人員一份參考指南。css
根據我建立Kraken的經驗,首先說明如何使用Angular/Cli生成此類項目, 而後進行共享資源和單元測試,並給出有關部署的提示html
首先,讓咱們要知道什麼是angular Workspace Workspace是一組angular應用程序和庫。angular.json
是Angular Workspace 的根級別文件爲構建和開發工具提供了工做區範圍和特定於項目(應用程序或庫)的配置默認值。前端
但願可使用Angular cli
生成Angular工做空間及其配置。就是本文章的主題:如何使用angular Cli 生成工做空間和其應用程序和庫。java
請記住,在Angular術語中項目既能夠是應用程序,也能夠是庫。二者都存儲在projects工做區的文件夾中, 並在根angular.json
文件中進行配置。node
Angular須要Node.js版本10.9.0
或更高版本(運行node -v
查看當前版本)。 Angular cli生成的Angular應用程序都依賴於以npm軟件包的形式提供的外部庫。 Node.js包含一個npm軟件包管理器。運行npm -v
以檢查npm版本。我建議使用命令將npm更新到最新的可用版本 (在本博客發佈時爲6.10.0) npm install -g npm@latest
。nginx
最後,你須要Angular Cli, 使用如下命令在全局安裝它:git
npm install -g @angular/cli
複製代碼
ng new <name>
命令用戶生成工做空間github
ng new kraken --createApplication=false --directory=frontend --interactive=false
複製代碼
--createApplication=false
參數避免建立初始應用程序(默認值爲true)。不然,Angular CLI src在新工做空間的文件夾中建立一個應用程序。在工做空間的子文件夾(projects)中生成應用程序。--interactive=false
參數用在此處,用以免angular cli建立項目時提示無用的參數,例如初始應用程序(咱們不生成)是否應包含路由模塊或要使用的CSS預處理程序。--directory=frontend
參數是初始化工做空間的目錄名稱。默認爲工做空間名稱。 正如咱們在上面的屏幕截圖中看到的那樣,此命令在frontend
文件夾中生成了幾個文件chrome
第一個是Angular Workspace配置文件 angular.json
。目前,它僅包含有關項目(應用程序和庫) 位置的信息。一旦咱們生成了一些東西,它將變得很是複雜。
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {}
}
複製代碼
該package.json文件列出了Angular所需的全部依賴關係。 因爲該ng new命令還安裝了npm依賴項,所以將生成package-lock.json文件 以及包含下載的依賴項的node_modules文件夾。
tsconfig.json文件指定打字稿編譯器選項(anuglar項目使用TS)。 而tslint.json文件配置打字稿短絨,是一個工具,用於分析源代碼, 標記編程錯誤,錯誤,文體錯誤,以及可疑的構造。
最後,README.md還會生成一個文件。 閱讀該文檔以獲取與Angular CLI用法有關的信息:如何構建,服務和測試新生成的應用程序
ng generate application <name>
命令用於projects在工做區的子文件夾中建立新的應用程序。 運行如下命令以生成兩個應用程序:Administration和Gatling:
cd frontend
ng generate application administration --style=scss --routing=true
ng generate application gatling --style=scss --routing=true
複製代碼
這些命令在子文件夾projects生成administration、gatling兩個項目,其中包含的文件以下(和常規的angular cli生成的項目,缺乏package.json文件)
命令也更新了根angular.json文件,添加了兩個應用程序配置:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"administration": {
"projectType": "application",
[...]
},
"gatling": {
"projectType": "application",
[...]
}
},
"defaultProject": "administration"
}
複製代碼
咱們稍後將瞭解針對每一個應用程序項目的配置,由於咱們將必須更新它們以共享資源。
ng generate library <name>
命令用於生成庫。 在工做空間文件夾中(frontend若是您遵循本教程的介紹),請運行如下命令:
ng generate library tools
ng generate library vendors
複製代碼
再次在這裏,angular.json使用兩個新建立的庫更新文件:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"administration": {
[...]
},
"gatling": {
[...]
},
"tools": {
"projectType": "library",
[...]
}
},
"vendors": {
"projectType": "library",
[...]
}
},
"defaultProject": "administration"
}
複製代碼
它還爲每一個庫projects/tools和projects/vendors建立相應的文件。文件與應用程序生成時的文件相似。
要注意的一件事是,在生成庫時不能指定樣式預處理器。angular.json庫的工做空間配置(文件)中沒有與此相關的配置。您每次在庫中生成組件時都必須指定樣式,例如使用command ng generate component my-component --style=scss --project=tools
。
這裏的想法是在庫中生成服務,並在應用程序中使用它。 讓咱們在tools庫中建立一個虛擬服務:
ng generate service hello-world --project=tools
複製代碼
語法是,ng generate service <service-name>
而且該參數--project是必需的,以指定在那個庫中生成服務。
這將建立一個文件projects/tools/src/hello-world.service.ts及其單元測試(projects/tools/src/hello-world.service.spec.ts)。更新它以建立一個簡單的getter:
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HelloWorldService {
get message(): string {
return 'Hello World!';
}
}
複製代碼
注意:該服務經過providedIn: 'root'選項聲明爲可注入。這意味着該服務是單例。它能夠在任何組件或服務中使用,而無需提供它。不管您在哪裏使用它,它始終是同一實例。
若是沒有此選項,咱們可能會使用每一個實例的語法爲每一個實例注入一個實例@Component({providers: [HelloWorldService]})。咱們也可使用語法在模塊級別執行相同的操做@NgModule({providers: [HelloWorldService]})。
在Angular文檔中閱讀有關依賴注入的更多信息。
複製代碼
更新AppComponent projects/administration/src/app/app.component.ts
使用上面的服務
import {Component} from '@angular/core';
import {HelloWorldService} from 'projects/tools/src/lib/hello-world.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'administration';
constructor(helloWorld: HelloWorldService) {
this.title = helloWorld.message;
}
}
複製代碼
若是使用的是IntelliJIdea
或Webstorm
,則HelloWorld
服務的默認導入爲 import {HelloWorldService} from '../../../tools/src/lib/hello-world.service';
。 若是您四處移動文件,這將很醜陋且難以維護。您能夠打開項目設置,而後選擇TypeScript>導入>「 使用相對於tsconfig.json的路徑」選項:
Angular Material UI
Angular Material是一組遵循Material Design設置的約定的組件。 藉助Angular CLI,只需運行如下命令便可在兩個應用程序上安裝Angular Material。
ng add @angular/material
ng add @angular/material --project=gatling
複製代碼
注意:第一個命令不須要--project=administration參數,由於它是工做區配置中的默認項目("defaultProject": "administration"在angular.json文件中)。
複製代碼
這兩個命令在package.json文件中添加依賴項@angular/material,還自動更新各類項目文件,添加適當的樣式,導入字體和NgModules:
UPDATE projects/administration/src/main.ts (391 bytes)
UPDATE projects/administration/src/app/app.module.ts (502 bytes)
UPDATE angular.json (10132 bytes)
UPDATE projects/administration/src/index.html (482 bytes)
UPDATE projects/administration/src/styles.scss (181 bytes)
複製代碼
我發現將外部依賴項從新組合到單個NgModule中更加乾淨。 這就是爲何咱們以前建立了一個vendors庫。
所以,讓咱們更新VendorsModule文件projects/vendors/src/lib/vendors.module.ts以導入和導出MatButtonModule,從而在一個地方從新組合咱們的外部依賴項:
import {NgModule} from '@angular/core';
import {MatButtonModule} from '@angular/material';
@NgModule({
imports: [MatButtonModule],
exports: [MatButtonModule]
})
export class VendorsModule { }
複製代碼
而後,咱們在AppModule中導入VendorsModule projects/administration/src/app/app.module.ts:
@NgModule({
[...]
imports: [
VendorsModule,
],
[...]
})
export class AppModule { }
複製代碼
最後,使用mat-raised-buttonAppComponent中的指令 projects/administration/src/app/app.component.html:
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<div><img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,..."></div>
<button mat-raised-button color="primary" >Click Me!</button>
</div>
複製代碼
要爲Angular應用程序提供服務,需運行命令ng serve --project=administration。
而後,您能夠在http://localhost:4200/
上打開網頁:
若是按照本教程的每一個步驟進行操做,則應該看到「歡迎使用Hello World !」消息以及提出的材料「 Click Me!」按鈕。
不然,您能夠下載源代碼(僅npm install在啓動應用程序以前運行)。
若是您想看一個更復雜的應用程序,請轉到「 完整的應用程序示例」一章。
另請注意,若是要同時啓動administration和gatling應用程序,則會看到錯誤消息:
Port 4200 is already in use. Use '--port' to specify a different port.
Error: Port 4200 is already in use. Use '--port' to specify a different port.
複製代碼
須要使用--port選項 具體請官方文檔或者閱讀「 如何使用HAProxy服務多個角度的應用程序(下文有介紹)」一章以瞭解如何設置應用程序使用的默認端口。
讓咱們回到負載測試IDE。將像Kraken這樣的大型應用程序拆分爲幾個模塊和庫是很不錯的。 它簡化了維護並提升了代碼的可重用性。
關於可重用性,跨組件庫共享CSS樣式和資產,擁有徹底隔離的模塊可能會更乾淨一些, 可是因爲我全部的庫和應用程序都依賴於Angular Material, 由於我不想爲每一個項目重複導入代碼。
在上面的介紹中,咱們導入了默認的Angular Material主題之一。 爲了使Kraken具備IDE的外觀和感受,我想使用自定義Angular Material主題,其主題爲:
Kraken
的用戶界面要建立此UI,我必須建立幾個組件庫:
它們都使用位於工做區根目錄styles文件夾中的通用CSS 。 例如,自定義材質主題SCSS文件將初始化Material Design並聲明自定義顏色:
@import '../node_modules/@angular/material/theming';
[...]
$app-primary: mat-palette($mat-blue);
$app-accent: mat-palette($mat-green);
$app-info: mat-palette($mat-light-blue);
$app-success: mat-palette($mat-light-green);
$app-error: mat-palette($mat-deep-orange);
$app-background: mat-palette($mat-gray);
[...]
$mat-theme: (
[...]
);
@include angular-material-theme($mat-theme);
複製代碼
而且緊湊的Scss文件,聲明瞭用於更改組件密度的自定義CSS類:
@import 'app-padding';
@import 'app-font';
// Must also disable the ripple effect
@mixin compact-checkbox($size: 34px) {
$half: $size / 2;
.mat-checkbox-inner-container {
height: $half;
width: $half;
}
}
@mixin compact-button($size: 34px) {
.mat-icon-button {
width: $size;
height: $size;
line-height: $size * 0.9;
.ng-fa-icon {
font-size: $size * 0.5;
}
}
}
[...]
複製代碼
爲了在管理和加特林負載測試應用程序中使用這些SCSS文件, 咱們必須在Angular的工做區配置中聲明它們angular.json:
"stylePreprocessorOptions": {
"includePaths": [
"styles"
]
},
複製代碼
在stylePreprocessorOptions
必須加入到projects > administration / gatling > architect > build > options
。
在運行單元測試時,若是某些被測組件須要通用樣式,則可能會出現如下錯誤:
ERROR in ../icon/src/lib/icon/icon.component.scss
Module build failed (from /home/kojiro/workspaces/kraken/frontend/node_modules/sass-loader/lib/loader.js):
@import 'app-margin';
^
Can't find stylesheet to import.
複製代碼
在這種狀況下,只需將添加stylePreprocessorOptions
到 projects > my-project > architect > test > options
工做空間配置部分。
除了公共CSS文件外,您可能還但願在應用程序和庫之間共享資產。
例如,在Kraken的資產中,咱們存儲:
"assets": [
"projects/gatling/src/favicon.ico",
"projects/gatling/src/assets",
{
"glob": "**/*",
"input": "assets/",
"output": "assets/"
},
{
"glob": "**/worker-*.js",
"input": "node_modules/ace-builds/src-min/",
"output": "assets/ace/"
},
],
複製代碼
它首先聲明特定於Gatling應用程序的資產。 而後,它將使用語法"glob": "**/*"
將其包含在根資產文件夾中的全部文件。 最後,全部Ace方法都被複制到中assets/ace/
。
咱們還使用許多其餘與Ace代碼編輯器相關的javascript文件。 這些主題,模式和代碼段必須在Architect選項的scripts部分中聲明build:
"scripts": [
"node_modules/ace-builds/src-min/mode-xml.js",
"node_modules/ace-builds/src-min/mode-yaml.js",
"node_modules/ace-builds/src-min/ext-searchbox.js",
"node_modules/ace-builds/src-min/ext-language_tools.js",
"node_modules/ace-builds/src-min/ext-modelist.js",
"ext/mode-log.js",
"ext/theme-kraken.js",
"ext/snippets/scala.js"
]
複製代碼
不管您要使用資產和外部腳本實現什麼目標,建議您瀏覽一下Angular-Cli文檔頁面: Stories Asset Configuration。
Angular CLI容許您使用如下語法在特定項目上運行單元測試:
ng test --project=<my-project>
複製代碼
默認狀況下,它將連續運行單元測試,讓您知道它們是成功仍是失敗。 若是是使用fit而不是it在單元測試定義上運行該特定測試(您也能夠fdescribe在測試套件上使用)。
它會在帶有選項的文件夾中自動生成測試覆蓋率報告。 /coverage/my-project--watch=false --codeCoverage=true
我但願有一個報告能夠從新組合全部覆蓋率信息,並經過並行運行單元測試來加快測試執行速度。 所以,我建立了如下腳本:
#!/bin/bash
rm -rf coverage
rm -rf coverage-all
for dir in projects/*; do
if [["$dir" != *-e2e]]
then
prefix="projects/";
project=${dir#$prefix}; #Remove prefix
echo "$project"
ng test --watch=false --codeCoverage=true --sourceMap=true --project=$project &
fi
done
wait # Wait for all tasks to complete
./node_modules/istanbul/lib/cli.js report --dir ./coverage-all/ html
google-chrome ./coverage-all/index.html &
複製代碼
它對每一個不以結尾結尾的項目-e2e(這些都是端到端測試項目)並行運行單元測試, 而且覆蓋範圍平行。而後,使用Istanbul client彙總全部報告。 警告:若是您有多個項目,則此腳本將同時運行多個Web瀏覽器。它可能會在計算機運行時凍結您的計算機!
Istanbul須要JSON格式的報告才能進行彙總.所以,也要更新karma.conf.js文件。它們位於每一個應用程序或庫的根目錄。只需添加json報告:
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage/analysis'),
reports: ['html', 'lcovonly', 'json'],
fixWebpackSourcePaths: true
},
複製代碼
若是您想知道如何編寫單元測試,請查看有關測試的Angular文檔。
在Kraken中,咱們有兩個Angular應用程序:Administration
和Gatling
。
這個想法是要在不一樣的端口和base Href
上服務;而後將它們打包爲在相同端口上使用但使用不一樣的基本Href的docker映像。 將它們打包爲在相同端口上使用,但使用不一樣的base Href
的docker映像。
base Href
上部署Angular應用默認狀況下,Angular在相同的URL和端口上爲全部應用程序提供服務:http://localhost:4200
。
爲了可以在開發過程當中同時啓動兩個應用程序, 請在Angular工做區配置angular.json文件中更改其中一個的端口。 例如,在Kraken中,Gatling應用程序的serve架構師配置爲在端口4222上爲其提供服務:
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "gatling:build",
"port": 4222
},
"configurations": {
"production": {
"browserTarget": "gatling:build:production"
}
}
},
複製代碼
而後,ng serve使用如下參數運行命令:
ng serve --open --project=gatling --baseHref /gatling/
複製代碼
因爲參數和配置的緣由,它將經過URL http://localhost:4222/gatling
打開Web瀏覽器。
藉助Angular-Cli ng build命令能夠構建Angular應用程序:
ng build gatling --prod --baseHref /gatling/
複製代碼
一樣,這裏--baseHref /gatling/
用於指定base Href。 該應用程序內置於文件夾中dist/gatling
。 如下DOCKERFILE生成一個NGINX Docker映像,其中包含已構建的應用程序:
FROM nginx:1.15.9-alpine
ARG APPLICATION
COPY nginx.conf /etc/nginx/nginx.conf
WORKDIR /usr/share/nginx/html
COPY dist/$APPLICATION .
RUN ls -laR .
EXPOSE 80
複製代碼
ng build命令的輸出將複製到/usr/share/nginx/html圖像的文件夾中,並使用如下Nginx配置:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80 default_server;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
try_files $uri $uri/ /index.html;
}
}
}
複製代碼
運行如下命令以生成Docker映像:
docker build --rm=true -t gatling-ui:latest --build-arg APPLICATION=gatling .
複製代碼
HAProxy是一種開源軟件,可爲基於TCP和HTTP的應用程序提供高可用性代理服務器。 對於Kraken,咱們使用它在適當的Frontend上重定向HTTP請求,具體取決於base Href
(感謝path_beg/administration關鍵字)。 這是配置文件:
global
defaults
mode http
option forwardfor
option http-server-close
# Set the max time to wait for a connection attempt to a server to succeed
timeout connect 30s
# Set the max allowed time to wait for a complete HTTP request
timeout client 50s
# Set the maximum inactivity time on the server side
timeout server 50s
# handle the situation where a client suddenly disappears from the net
timeout client-fin 30s
frontend http-in
bind *:80
mode http
acl has_administration path_beg /administration
acl has_gatling path_beg /gatling
use_backend kraken-administration if has_administration
use_backend kraken-gatling if has_gatling
backend kraken-administration
server kraken-administration-ui kraken-administration-ui:80 check fall 3 rise 2
reqrep ^([^\ ]*\ /)administration[/]?(.*) \1\2
backend kraken-gatling
server kraken-gatling-ui kraken-gatling-ui:80 check fall 3 rise 2
reqrep ^([^\ ]*\ /)gatling[/]?(.*) \1\2
複製代碼
啓動它的最簡單方法是使用HAProxy Docker映像。
要查看完整的示例(使用啓動兩個前端應用程序,多個後端服務器和HAProxy docker-compose)。
我但願這篇博文對但願嘗試Angular開發複雜的多項目工做區的人有所幫助。
能夠在GitHub上找到Kraken的Angular前端的源代碼,請查看完整的最新代碼示例。若是您認爲我錯過了Angular開發的重要部分或犯了一個錯誤,請給我寫評論。
最後,若是您想了解有關負載測試IDE的Kraken的更多信息,請查看其GitHub頁面。
博文地址:地址