OctoPer’s load test IDE (Kraken) is an Angular project with multiple front-end applications,
- Admin UI for managing Docker containers and container images
- Both the Gatling UIs are based on Angular8 and share many components, CSS, and external library dependencies.
This post is intended as a reference guide for every Developer who wants to create an Angular Workspace with multiple applications and libraries.
Based on my experience in creating Kraken, first explain how to use Angular/Cli to generate such a project, then share resources and unit tests, and give tips on deployment
Angular multi-application project creation
First, let’s know what An Angular Workspace is. A Workspace is a set of Angular applications and libraries. Angular. json is the root level file of the Angular Workspace that provides Workspace scopes and project-specific (application or library) configuration defaults for build and development tools.
You want to be able to use the Angular CLI to generate an Angular workspace and its configuration. That’s the topic of this article: how to use the Angular Cli to generate workspaces and their applications and libraries.
Remember that projects can be either applications or libraries in Angular terms. Both are stored in the projects workspace folder and configured in the root angular.json file.
A prerequisite for
Angular requires Node.js version 10.9.0 or later (run Node -v to view the current version). Angular CLI-generated Angular applications rely on external libraries in the form of NPM packages. Node.js includes an NPM package manager. Run NPM -v to check the NPM version. I recommend using the command to update NPM to the latest available version (6.10.0 as of this blog post) NPM install -g npm@latest.
Finally, you need the Angular Cli to install it globally with the following command:
npm install -g @angular/cli
Copy the code
Create a Workspace
Ng new
command user to generate workspace
ng new kraken --createApplication=false --directory=frontend --interactive=false
Copy the code
--createApplication=false
Parameter to avoid creating an initial application (default is true). Otherwise, Angular CLI SRC creates an application in a folder in the new workspace. Build the application in a subfolder (Projects) in the workspace.--interactive=false
Parameters are used here to avoid prompting the Angular CLI to create a project with useless parameters, such as whether the initial application (which we don’t generate) should contain a routing module or a CSS preprocessor to use.--directory=frontend
The parameter is the name of the directory to initialize the workspace. Default is the workspace name.
As we can see in the screenshot above, this command generates several files in the Frontend folder
The first is the Angular Workspace configuration file angular.json. Currently, it contains only information about the location of projects (applications and libraries). Once we generate something, it gets really complicated.
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json"."version": 1."newProjectRoot": "projects"."projects": {}}Copy the code
The package.json file lists all dependencies Angular needs. Since the ng new command also installs NPM dependencies, the package-Lock. json file is generated along with the node_modules folder containing the downloaded dependencies.
The tsconfig.json file specifies typescript compiler options (TS is used by the Anuglar project). The tslint.json file configuration typescript short lint is a tool for analyzing source code and flagting programming errors, errors, stylistic errors, and suspicious constructs.
Finally, readme.md also generates a file. Read this document for information about Angular CLI usage: How to build, service, and test newly generated applications
Create an application
The ng generate application
command is used by projects to create a new application in a subfolder in the workspace. Run the following command to generate two applications: Administration and Gatling:
cd frontend
ng generate application administration --style=scss --routing=true
ng generate application gatling --style=scss --routing=true
Copy the code
- Parameter –style= SCSS Sets the SCSS preprocessor for the style file (default: CSS) — the parameter can be left out.
- The –routing=true argument tells the Angular CLI to generate a routing NgModule without it.
These commands generate administration and Gatling projects in the subfolder projects, which contain the following files (and regular Angular CLI-generated projects, missing package.json files)
- Two tsconfig.*.ts files. They extend the root of the workspace, tsconfig.ts, and set specific configurations to compile the application (tsconfig.app.ts) or its unit tests (tsconfig.spec.ts). Read more about TypeScript configuration in the Angular documentation.
- This SRC folder contains all TypeScript, HTML, and CSS sources for your application (more on SRC folder structure).
- Karma. Conf.js Karma configuration file for unit tests.
- E2e A folder for running end-to-end tests with protractors.
The command also updates the root angular.json file to add two application configurations:
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "administration": { "projectType": "application", [...] }, "gatling": { "projectType": "application", [...] } }, "defaultProject": "administration" }Copy the code
We’ll look at the configuration for each application project later, because we’ll have to update them to share resources.
Create a library (librany)
The ng generate library
command is used to generate a library. In the workspace folder (frontend if you follow the instructions in this tutorial), run the following command:
ng generate library tools
ng generate library vendors
Copy the code
Here again, angular.json updates files with two newly created libraries:
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "administration": { [...] }, "gatling": { [...] }, "tools": { "projectType": "library", [...] } }, "vendors": { "projectType": "library", [...] } }, "defaultProject": "administration" }Copy the code
It also creates files for each library, projects/ Tools and projects/vendors. The file is similar to the file when the application is generated.
One thing to note is that you cannot specify a style preprocessor when you build the library. There is no configuration related to this in the workspace configuration (file) of the Angular. json library. You must specify a style each time you generate a component in the library, for example using Command ng generate component my-component –style= SCSS –project=tools.
Creating a Shared Service
The idea here is to generate the service in the library and use it in the application. Let’s create a virtual service in the Tools library:
ng generate service hello-world --project=tools
Copy the code
The syntax is ng generate service
and the parameter –project is required to specify which library to generate the service in.
This will create a file called projects/tools/ SRC /hello-world.service.ts and its unit tests (projects/tools/ SRC /hello-world.service.spec.ts). Update it to create a simple getter:
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class HelloWorldService {
get message(): string {
return 'Hello World! '; }}Copy the code
Note: This service is declared injectable with the providedIn: 'root' option. This means that the service is a singleton. It can be used in any component or service without having to provide it. No matter where you use it, it's always the same instance. Without this option, we might inject an instance @Component({providers: [HelloWorldService]}) for each instance using the per-instance syntax. We can also use syntax to do the same thing at the module level @ngModule ({providers: [HelloWorldService]}). Read more about dependency injection in the Angular documentation.Copy the code
Update AppComponent projects/administration/src/app/app.com ponent. Ts with the above services
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; }}Copy the code
Student: If you use thetaIntelliJIdea
orWebstorm
,HelloWorld
The default import of the service isimport {HelloWorldService} from '.. /.. /.. /tools/src/lib/hello-world.service';
. If you move files around, this can be ugly and difficult to maintain. You can open project Settings and choose TypeScript> Import > Use path relative to tsconfig.json:
The installationAngular Material UI
Angular Material is a set of components that follow the conventions of Material Design Settings. With the Angular CLI, you can install Angular Material on both applications by simply running the following command.
ng add @angular/material
ng add @angular/material --project=gatling
Copy the code
Note: the first command does not require the --project=administration parameter because it is the defaultProject in the workspace configuration ("defaultProject": "administration" in the angular.json file).Copy the code
These two commands add a dependency @angular/material to the package.json file and also automatically update various project files to add appropriate styles and import fonts and 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)
Copy the code
I found it much cleaner to regroup external dependencies into a single NgModule. That’s why we created a vendors library earlier.
So, let’s update VendorsModule file projects/vendors/SRC/lib/vendors. The module. The ts to import and export MatButtonModule, thus in one place rearrange our external dependencies:
import {NgModule} from '@angular/core';
import {MatButtonModule} from '@angular/material';
@NgModule({
imports: [MatButtonModule],
exports: [MatButtonModule]
})
export class VendorsModule { }
Copy the code
Then, we import in the AppModule VendorsModule projects/administration/SRC/app/app. The module. The ts:
@NgModule({[...]. imports: [ VendorsModule, ], [...] })export class AppModule { }
Copy the code
Finally, using the instructions of the mat – raised – buttonAppComponent projects/administration/src/app/app.com ponent. 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>
Copy the code
Start the application
To serve an Angular application, run the command ng serve –project=administration.
You can then open the web page at http://localhost:4200/ :
If you follow each step in this tutorial, you should see “Welcome to Hello World!” Message and presented material “Click Me! Button.
Otherwise, you can download the source code (only NPM Install runs before starting the application).
If you want to see a more complex application, go to the “Complete Application Example” chapter.
Also notice that if you want to start both the Administration and Gatling applications, you see error messages:
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.
Copy the code
Use the –port option for details please refer to the official documentation or read the chapter “How to Use HAProxy to Serve Multi-angle applications (described below)” to learn how to set the default port used by your application.
Angular shares resources with multiple applications
Let’s go back to the load test IDE. Splitting a large application like Kraken into several modules and libraries is a good idea. It simplifies maintenance and improves code reusability.
In terms of reusability, sharing CSS styles and assets across component libraries, it might be cleaner to have completely isolated modules, but since all my libraries and applications rely on Angular Material, I don’t want to import code repeatedly for every project.
Libraries and applications share CSS
In the introduction above, we imported one of the default Angular Material themes. To give Kraken the look and feel of an IDE, I want to use a custom Angular Material theme with the following theme:
- Dark background
- The color is better than the basic main color and other warning colors (add warning, success, danger and other colors),
- Components are more densely laid out (there is no layer density yet).
Kraken
The user interface of
To create this UI, I had to create several component libraries:
- Adjustable split panel,
- Console and file tree tabs,
- Code editor,
- And a master workspace that combines all of this.
They all use generic CSS located in the styles folder at the root of the workspace. For example, the custom Material theme SCSS file initializes Material Design and declares custom colors:
@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);
Copy the code
And a compact Scss file that declares custom CSS classes for changing component density:
@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; }}}[...].
Copy the code
To use these SCSS files in management and Gatling load testing applications, we must declare them in Angular workspace configuration angular.json:
"stylePreprocessorOptions": {
"includePaths": [
"styles"
]
},
Copy the code
In stylePreprocessorOptions you must join Projects > Administration/Gatling > Architect > Build > Options.
When running unit tests, the following error may occur if some of the components under test require a common style:
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.Copy the code
In this case, simply add stylePreprocessorOptions to the Projects > My-Project > Architect > Test > Options workspace configuration section.
Sharing assets across libraries and applications
In addition to common CSS files, you may want to share assets between applications and libraries.
For example, in Kraken’s assets, we store:
- Kraken logo,
- Javascript files used by Ace editor. In fact, due to configuration, the Ace theme and schema files are in the Ext folder and have been copied angular.json. For example, the Gatling Build Architect option includes the following configuration:
"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/"},].Copy the code
It begins by declaring assets specific to the Gatling application. It then uses the syntax “glob”: “**/*” to include all the files in the root assets folder. Finally, all Ace methods are copied into assets/ Ace /.
We also use a number of other javascript files associated with the Ace code editor. These themes, patterns, and code segments must be declared build in the Scripts section of the Architect option:
"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"
]
Copy the code
Whatever you want to accomplish with assets and external scripts, you are advised to take a look at the Angular-CLI documentation page: Stories Asset Configuration.
Angular workspaces and unit tests
The Angular CLI allows you to run unit tests on specific projects using the following syntax:
ng test --project=<my-project>
Copy the code
-
By default, it will run unit tests continuously to let you know if they succeeded or failed. If you are running this particular test on a unit test definition using FIT rather than IT (you can also use FDESCRIBE on a test suite).
-
It automatically generates test coverage reports in folders with options. /coverage/my-project–watch=false –codeCoverage=true
I want a report that recombines all coverage information and speeds up test execution by running unit tests in parallel. Therefore, I created the following script:
#! /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 &
Copy the code
It runs unit tests in parallel, with parallel coverage, for each project that does not end at the end – E2E (these are all end-to-end test projects). Then, use the Istanbul Client to assemble all the reports. Warning: If you have multiple projects, this script will run multiple Web browsers at the same time. It may freeze your computer while it is running!
Istanbul needs a JSON report to put it together. Therefore, update the karmap.conf.js file as well. They are located at the root of each application or library. Simply add the JSON report:
coverageIstanbulReporter: { dir: require('path').join(__dirname, '.. /.. /coverage/analysis'), reports: ['html', 'lcovonly', 'json'], fixWebpackSourcePaths: true },Copy the code
If you want to know how to write unit tests, check out the Angular documentation for tests.
How to use the HAProxy service to serve multiple Angular applications
In Kraken, we have two Angular applications: Administration and Gatling.
The idea is to serve on different ports and base Href; They are then packaged as docker images that are used on the same port but with a different base Href. Package them as docker images for use on the same port, but with different base Href.
In particular ports andbase Href
Deploy the Angular application on
By default, Angular serves all applications at the same URL and port: http://localhost: 4200.
To be able to launch both applications during development, change the port of one of them in the Angular Workspace configuration Angular. json file. For example, in Kraken, the Serve architect for the Gatling application is configured to service it on port 4222:
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "gatling:build",
"port": 4222
},
"configurations": {
"production": {
"browserTarget": "gatling:build:production"
}
}
},
Copy the code
Ng serve then runs the command with the following parameters:
ng serve --open --project=gatling --baseHref /gatling/
Copy the code
Due to the parameter and configuration, it will open Web browser via the URL http://localhost:4222/gatling.
Package Angular apps as Docker images
Angular applications can be built with the angular-cli ng build command:
ng build gatling --prod --baseHref /gatling/
Copy the code
Again, here –baseHref /gatling/ is used to specify the baseHref. The application is built into the folder Dist/Gatling. The following DOCKERFILE generates an NGINX Docker image containing the built application:
FROM nginx:1.15.9-alpine ARG APPLICATION COPY nginx.conf /etc/nginx.conf WORKDIR /usr/share/nginx.html COPY dist/$APPLICATION .
RUN ls -laR .
EXPOSE 80
Copy the code
The output of the ng build command is copied to a folder of /usr/share/nginx/html images using the following nginx configuration:
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; }}}Copy the code
Run the following command to generate the Docker image:
docker build --rm=true -t gatling-ui:latest --build-arg APPLICATION=gatling .
Copy the code
Use HAProxy to provide production mirroring
HAProxy is open source software that provides a highly available proxy server for TCP – and HTTP-based applications. For Kraken, we use it to redirect HTTP requests on the appropriate Frontend, depending on the base Href (thanks to the path_beg/administration keyword). Here is the configuration file:
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 ifhas_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 (. *)Copy the code
The easiest way to start it is to use the HAProxy Docker image.
To see the full example (using starting two front-end applications, multiple back-end servers, and HAProxy Docker-compose).
Complete application
I hope this blog post has been helpful to anyone who wants to try out the complexities of Angular development in a multi-project workspace.
The source code for Kraken’s Angular front-end is available on GitHub. Check out the full, up-to-date code sample. If you think I missed an important part of Angular development or made a mistake, please leave me a comment.
Finally, if you want to learn more about Kraken for the load testing IDE, check out its GitHub page.
Blog address: address
Original address:
The original address