openvidu-components: Added webcomponent

Now it's possible generate a webcomponent using the openvidu-angular library.
pull/688/head
csantosm 2022-01-24 11:18:23 +01:00
parent 46c7516764
commit a73230ac79
12 changed files with 2956 additions and 2223 deletions

2
.gitignore vendored
View File

@ -31,3 +31,5 @@ openvidu-components-angular/node_modules/
openvidu-components-angular/.angular/
openvidu-components-angular/dist/
openvidu-components-angular/openvidu-webcomponent/

View File

@ -1,172 +1,212 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"openvidu-components-testapp": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/openvidu-components-testapp",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"development": {
"optimization": false,
"outputHashing": "all",
"sourceMap": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "openvidu-components-testapp:build",
"proxyConfig": "src/proxy.config.json"
},
"configurations": {
"development": {
"browserTarget": "openvidu-components-testapp:build:development"
},
"production": {
"browserTarget": "openvidu-components-testapp:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "openvidu-components-testapp:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "openvidu-components-testapp:serve"
},
"configurations": {
"production": {
"devServerTarget": "openvidu-components-testapp:serve:production"
}
}
}
}
},
"openvidu-angular": {
"projectType": "library",
"root": "projects/openvidu-angular",
"sourceRoot": "projects/openvidu-angular/src",
"prefix": "ov",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/openvidu-angular/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/openvidu-angular/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/openvidu-angular/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/openvidu-angular/src/test.ts",
"tsConfig": "projects/openvidu-angular/tsconfig.spec.json",
"karmaConfig": "projects/openvidu-angular/karma.conf.js"
}
}
}
}},
"defaultProject": "openvidu-components-testapp"
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"openvidu-components-testapp": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/openvidu-components-testapp",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
},
"configurations": {
"development": {
"optimization": false,
"outputHashing": "all",
"sourceMap": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "openvidu-components-testapp:build",
"proxyConfig": "src/proxy.config.json"
},
"configurations": {
"development": {
"browserTarget": "openvidu-components-testapp:build:development"
},
"production": {
"browserTarget": "openvidu-components-testapp:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "openvidu-components-testapp:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "openvidu-components-testapp:serve"
},
"configurations": {
"production": {
"devServerTarget": "openvidu-components-testapp:serve:production"
}
}
}
}
},
"openvidu-angular": {
"projectType": "library",
"root": "projects/openvidu-angular",
"sourceRoot": "projects/openvidu-angular/src",
"prefix": "ov",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/openvidu-angular/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/openvidu-angular/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/openvidu-angular/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/openvidu-angular/src/test.ts",
"tsConfig": "projects/openvidu-angular/tsconfig.spec.json",
"karmaConfig": "projects/openvidu-angular/karma.conf.js"
}
}
}
},
"openvidu-webcomponent": {
"projectType": "application",
"root": "",
"sourceRoot": "src",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/openvidu-webcomponent",
"index": "src/index.html",
"main": "src/app/openvidu-webcomponent/openvidu-webcomponent.main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/app/openvidu-webcomponent/tsconfig.openvidu-webcomponent.json",
"aot": true,
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"src/app/openvidu-webcomponent/openvidu-webcomponent.component.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "none",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "1mb",
"maximumError": "2mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
]
}
}
}
}
}
},
"defaultProject": "openvidu-components-testapp"
}

View File

@ -0,0 +1,69 @@
const fs = require("fs-extra");
const concat = require("concat");
const VERSION = require("./package.json").version;
module.exports.buildWebcomponent = async () => {
console.log("Building OpenVidu Web Component (" + VERSION + ")");
const tutorialWcPath = "../../openvidu-tutorials/openvidu-webcomponent/web";
const e2eWcPath = "../webcomponent-test-e2e/web";
try {
await buildElement();
await copyFiles(tutorialWcPath);
await copyFiles(e2eWcPath);
console.log("OpenVidu Web Component (" + VERSION + ") built");
} catch (error) {
console.error(error);
}
};
async function buildElement() {
const files = [
// "./dist/openvidu-call/runtime.js",
// "./dist/openvidu-call/polyfills.js",
// "./dist/openvidu-call/scripts.js",
// "./dist/openvidu-call/main.js",
"./dist/openvidu-webcomponent/runtime.js",
"./dist/openvidu-webcomponent/main.js",
"./dist/openvidu-webcomponent/polyfills.js",
// "./dist/openvidu-webcomponent/scripts.js",
];
try {
await fs.ensureDir("openvidu-webcomponent");
await concat(
files,
"./openvidu-webcomponent/openvidu-webcomponent-" + VERSION + ".js"
);
await fs.copy(
"./dist/openvidu-webcomponent/styles.css",
"./openvidu-webcomponent/openvidu-webcomponent-" + VERSION + ".css"
);
await fs.copy(
"./dist/openvidu-webcomponent/assets",
"./openvidu-webcomponent/assets"
);
} catch (err) {
console.error("Error executing build function in webcomponent-builds.js");
throw err;
}
}
async function copyFiles(destination) {
if (fs.existsSync(destination)) {
try {
console.log(
"Copying openvidu-webcomponent files from: ./openvidu-webcomponent to: " +
destination
);
await fs.ensureDir("openvidu-webcomponent");
await fs.copy("./openvidu-webcomponent/", destination);
} catch (err) {
console.error("Error executing copy function in webcomponent-builds.js");
throw err;
}
}
}
this.buildWebcomponent();

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,8 @@
"lib:build": "ng build openvidu-angular --configuration production && cd ./dist/openvidu-angular && npm pack",
"lib:copy": "cp dist/openvidu-angular/openvidu-angular-*.tgz ../openvidu-tutorials/openvidu-angular-components",
"lib:test": "ng test openvidu-angular --no-watch --code-coverage",
"webcomponent:build": "./node_modules/@angular/cli/bin/ng.js build openvidu-webcomponent --configuration production && node ./openvidu-webcomponent-build.js",
"bundle-report": "ng build openvidu-webcomponent --stats-json --configuration production && webpack-bundle-analyzer dist/openvidu-webcomponent/stats.json",
"lint": "ng lint",
"e2e": "ng e2e"
},
@ -16,15 +18,15 @@
"@angular/animations": "13.0.0",
"@angular/cdk": "13.0.0",
"@angular/common": "13.0.0",
"@angular/compiler": "13.0.0",
"@angular/core": "13.0.0",
"@angular/flex-layout": "12.0.0-beta.35",
"@angular/flex-layout": "13.0.0-beta.36",
"@angular/forms": "13.0.0",
"@angular/material": "13.0.0",
"@angular/platform-browser": "13.0.0",
"@angular/platform-browser-dynamic": "13.0.0",
"@angular/router": "13.0.0",
"autolinker": "3.14.3",
"buffer": "^6.0.3",
"openvidu-browser": "2.21.0-beta1",
"rxjs": "7.4.0",
"tslib": "2.3.1",
@ -33,11 +35,14 @@
"devDependencies": {
"@angular-devkit/build-angular": "13.0.1",
"@angular/cli": "13.0.1",
"@angular/compiler": "13.0.0",
"@angular/compiler-cli": "13.0.0",
"@angular/elements": "13.0.0",
"@types/jasmine": "3.10.2",
"@types/jasminewd2": "2.0.10",
"@types/node": "16.11.6",
"codelyzer": "6.0.2",
"concat": "^1.0.3",
"jasmine-core": "3.10.1",
"jasmine-spec-reporter": "7.0.0",
"karma": "^6.3.9",
@ -53,6 +58,7 @@
"protractor": "7.0.0",
"ts-node": "10.4.0",
"tslint": "6.1.3",
"typescript": "4.4.4"
"typescript": "4.4.4",
"webpack-bundle-analyzer": "^4.5.0"
}
}

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit, Output } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { RestService } from '../../services/rest/rest.service';
@Component({
@ -11,7 +11,7 @@ export class VideoconferenceComponent implements OnInit {
@Input() userName: string;
@Input() openviduServerUrl: string;
@Input() openviduSecret: string;
@Input() tokens: string[];
@Input() tokens: { webcam: string; screen: string };
joinSessionClicked: boolean = false;
closeClicked: boolean = false;
@ -25,8 +25,7 @@ export class VideoconferenceComponent implements OnInit {
ngOnInit() {}
async onJoinClicked() {
if (!this.tokens || this.tokens?.length === 0) {
if (!this.tokens || (!this.tokens?.webcam && !this.tokens?.screen)) {
//No tokens received
if (!!this.sessionName && !!this.openviduServerUrl && !!this.openviduSecret) {
@ -41,17 +40,18 @@ export class VideoconferenceComponent implements OnInit {
this.errorMessage = `Cannot access to OpenVidu Server with url '${this.openviduServerUrl}' to genere tokens for session '${this.sessionName}'`;
throw this.errorMessage;
}
} else if (this.tokens?.length < 2) {
} else if (!this.tokens?.webcam || !this.tokens?.screen) {
// 1 token received
const aditionalToken = await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret);
this._tokens = {
webcam: this.tokens[0],
screen: await this.restService.getToken(this.sessionName, this.openviduServerUrl, this.openviduSecret)
webcam: !!this.tokens.webcam ? this.tokens.webcam : aditionalToken,
screen: !!this.tokens.screen ? this.tokens.screen : aditionalToken
};
} else {
// 2 tokens received.
this._tokens = {
webcam: this.tokens[0],
screen: this.tokens[1]
webcam: this.tokens.webcam,
screen: this.tokens.screen
};
}
this.joinSessionClicked = true;

View File

@ -7,7 +7,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { environment } from 'src/environments/environment';
// openvidu-components-angular
// openvidu-angular
import { CallComponent } from './openvidu-call/call.component';
import { ToolbarTestComponent } from './components/toolbar-test/toolbar-test.component';

View File

@ -0,0 +1,73 @@
@use '@angular/material' as mat;
@import '~@angular/material/theming';
// Plus imports for other components in your app.
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$openvidu-components-primary: mat-palette($mat-blue-grey, 50, 300);
$openvidu-components-accent: mat-palette($mat-amber, 500, 700, A100);
// The warn palette is optional (defaults to red).
$openvidu-components-warn: mat.define-palette(mat.$red-palette);
// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$openvidu-components-theme: mat.define-light-theme((
color: (
primary: $openvidu-components-primary,
accent: $openvidu-components-accent,
warn: $openvidu-components-warn,
)
));
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include mat.all-component-themes($openvidu-components-theme);
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/materialicons/v38/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
// Default openvidu-webcomponent colors
:root {
--ov-primary-color: #303030;
--ov-secondary-color: #586063;
--ov-tertiary-color: #598eff;
--ov-warn-color: #EB5144;
--ov-accent-color: #ffae35;
--ov-dark-color: #1d1d1d;
--ov-dark-light-color: #43484A;
--ov-light-color: #ffffff;
--ov-light-dark-color: #f1f1f1;
}

View File

@ -0,0 +1,69 @@
import { Component, Input, OnInit } from "@angular/core";
export interface SessionConfig {
sessionName: string;
userName: string;
tokens: { webcam: string; screen: string };
}
@Component({
template: ` <ov-videoconference
*ngIf="successParams"
[sessionName]="sessionConfig.sessionName"
[userName]="sessionConfig.userName"
[openviduServerUrl]="openviduServerUrl"
[openviduSecret]="openviduSecret"
[tokens]="sessionConfig.tokens"
></ov-videoconference>`,
})
export class OpenviduWebComponentComponent implements OnInit {
@Input() openviduServerUrl: string;
@Input() openviduSecret: string;
successParams: boolean = false;
constructor() {}
ngOnInit(): void {}
@Input("sessionConfig")
set sessionConfig(config: SessionConfig | string) {
console.log("Webcomponent sessionConfig: ", config);
// setTimeout(() => {
if (typeof config === "string") {
try {
config = JSON.parse(config);
} catch (error) {
console.error("Unexpected JSON", error);
}
} else {
if (this.isEmpty(config)) {
// Leaving session when sessionConfig is empty
} else {
this.successParams = this.isCorrectParams(config);
if (!this.successParams) {
console.error("Parameters received are incorrect: ", config);
console.error("Session cannot start");
}
}
}
// }, 200);
}
private isCorrectParams(config: SessionConfig): boolean {
const canGenerateToken =
!!config.sessionName &&
!!config.userName &&
!!this.openviduServerUrl &&
!!this.openviduSecret;
const hasToken =
!!config.tokens?.webcam && !!config.tokens?.screen && !!config.userName;
return canGenerateToken || hasToken;
}
private isEmpty(config: SessionConfig): boolean {
return Object.keys(config).length === 0;
}
}

View File

@ -0,0 +1,11 @@
import { OpenviduWebComponentModule } from './openvidu-webcomponent.module';
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { environment } from "../../environments/environment";
if (environment.production) {
enableProdMode();
}
const bootstrap = () => platformBrowserDynamic().bootstrapModule(OpenviduWebComponentModule);
bootstrap().catch(err => console.error(err));

View File

@ -0,0 +1,37 @@
import { BrowserModule } from "@angular/platform-browser";
import { DoBootstrap, Injector, NgModule } from "@angular/core";
import { APP_BASE_HREF, CommonModule } from "@angular/common";
import { createCustomElement, NgElement, WithProperties } from "@angular/elements";
import { OpenviduWebComponentComponent } from "./openvidu-webcomponent.component";
import { OpenviduAngularModule, VideoconferenceComponent } from "openvidu-angular";
import { environment } from '../../environments/environment';
declare global {
interface HTMLElementTagNameMap {
'openvidu-webcomponent': NgElement & WithProperties<{ openviduServerUrl: string, openviduSecret: string}>;
}
}
@NgModule({
declarations: [OpenviduWebComponentComponent],
imports: [
CommonModule,
BrowserModule,
OpenviduAngularModule.forRoot(environment),
],
// exports: [OpenviduWebComponentComponent],
providers: [{provide: APP_BASE_HREF, useValue: '/'} , VideoconferenceComponent],
})
export class OpenviduWebComponentModule implements DoBootstrap {
constructor(private injector: Injector) {}
ngDoBootstrap(): void {
const element = createCustomElement(OpenviduWebComponentComponent, {
injector: this.injector,
});
customElements.define("openvidu-webcomponent", element);
}
}

View File

@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "../../../out-tsc/app",
"types": [],
"paths": {
"openvidu-angular": [
"dist/openvidu-angular"
]
}
},
"files": [
"./openvidu-webcomponent.main.ts",
"../../polyfills.ts"
],
"include": [
"src/**/*.d.ts"
]
}