From d9f0246548f785ffc6234f7dcabe1e5f018aaec4 Mon Sep 17 00:00:00 2001 From: Dave Skender <8432125+DaveSkender@users.noreply.github.com> Date: Thu, 22 Aug 2024 00:06:18 -0400 Subject: [PATCH] feat: Service worker, perf tuning (#356) --- Client/angular.json | 13 +--- Client/package-lock.json | 20 ++++++ Client/package.json | 1 + Client/src/app/app.module.ts | 2 +- Client/src/app/chart/chart.module.ts | 38 +++++++----- Client/src/app/picker/settings.module.ts | 69 ++++++++++++--------- Client/src/ngsw-config.json | 44 +++++++++++++ Server/WebApi/Controllers/MainController.cs | 8 ++- 8 files changed, 137 insertions(+), 58 deletions(-) create mode 100644 Client/src/ngsw-config.json diff --git a/Client/angular.json b/Client/angular.json index 679525b0..4667037c 100644 --- a/Client/angular.json +++ b/Client/angular.json @@ -72,18 +72,9 @@ "with": "src/environments/environment.prod.ts" } ], - "optimization": { - "styles": { - "minify": true, - "inlineCritical": true - }, - "scripts": true, - "fonts": { - "inline": true - } - }, + "optimization": true, "outputHashing": "all", - "sourceMap": true, + "sourceMap": false, "namedChunks": false, "extractLicenses": true, "budgets": [ diff --git a/Client/package-lock.json b/Client/package-lock.json index 812b8bf6..c3550e0e 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -16,6 +16,7 @@ "@angular/platform-browser": "18.2.0", "@angular/platform-browser-dynamic": "18.2.0", "@angular/router": "18.2.0", + "@angular/service-worker": "18.2.0", "@ctrl/tinycolor": "4.1.0", "@ng-matero/extensions": "18.2.0", "chart.js": "4.4.4", @@ -852,6 +853,25 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@angular/service-worker": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.2.0.tgz", + "integrity": "sha512-ngcALrgqMuAeIo5dgou6eBzdtgLvmVg5zwmZuTyrnNPZENEaKTj7u5pm9++gl62797sUWlMbL+fa/BOhntGs5A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "bin": { + "ngsw-config": "ngsw-config.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/common": "18.2.0", + "@angular/core": "18.2.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", diff --git a/Client/package.json b/Client/package.json index 0e82ef2c..ea1c52a2 100644 --- a/Client/package.json +++ b/Client/package.json @@ -19,6 +19,7 @@ "@angular/platform-browser": "18.2.0", "@angular/platform-browser-dynamic": "18.2.0", "@angular/router": "18.2.0", + "@angular/service-worker": "18.2.0", "@ctrl/tinycolor": "4.1.0", "@ng-matero/extensions": "18.2.0", "chart.js": "4.4.4", diff --git a/Client/src/app/app.module.ts b/Client/src/app/app.module.ts index e643ed18..b68f17b6 100644 --- a/Client/src/app/app.module.ts +++ b/Client/src/app/app.module.ts @@ -3,7 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CommonModule } from '@angular/common'; -import { MatButtonModule as MatButtonModule } from '@angular/material/button'; +import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; diff --git a/Client/src/app/chart/chart.module.ts b/Client/src/app/chart/chart.module.ts index ebc194c1..f2508324 100644 --- a/Client/src/app/chart/chart.module.ts +++ b/Client/src/app/chart/chart.module.ts @@ -13,19 +13,27 @@ import { ChartComponent } from './chart.component'; import { ChartService } from '../services/chart.service'; -@NgModule({ declarations: [ - ChartComponent - ], - exports: [ - ChartComponent - ], - bootstrap: [ChartComponent], imports: [CommonModule, - MatButtonModule, - MatDialogModule, - MatIconModule, - MatToolbarModule, - MatTooltipModule], providers: [ - ChartService, - provideHttpClient(withInterceptorsFromDi()) - ] }) +@NgModule({ + declarations: [ + ChartComponent + ], + exports: [ + ChartComponent + ], + bootstrap: [ + ChartComponent + ], + imports: [ + CommonModule, + MatButtonModule, + MatDialogModule, + MatIconModule, + MatToolbarModule, + MatTooltipModule + ], + providers: [ + ChartService, + provideHttpClient(withInterceptorsFromDi()) + ] +}) export class ChartModule { } diff --git a/Client/src/app/picker/settings.module.ts b/Client/src/app/picker/settings.module.ts index 786f24da..c678857f 100644 --- a/Client/src/app/picker/settings.module.ts +++ b/Client/src/app/picker/settings.module.ts @@ -32,34 +32,43 @@ import { PickConfigComponent } from './pick-config.component'; import { ChartService } from '../services/chart.service'; import { ApiService } from '../services/api.service'; -@NgModule({ declarations: [ - SettingsComponent, - PickConfigComponent - ], - exports: [ - SettingsComponent, - PickConfigComponent - ], - bootstrap: [], imports: [CommonModule, - FormsModule, - MatBottomSheetModule, - MatButtonModule, - MatCheckboxModule, - MatDialogModule, - MatFormFieldModule, - MatIconModule, - MatInputModule, - MatListModule, - MatSelectModule, - MatSlideToggleModule, - MatTabsModule, - MatToolbarModule, - MatTooltipModule, - MtxColorpickerModule, - ColorCompactModule], providers: [ - ChartService, - ApiService, - { provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }, - provideHttpClient(withInterceptorsFromDi()) - ] }) +@NgModule({ + declarations: [ + SettingsComponent, + PickConfigComponent + ], + exports: [ + SettingsComponent, + PickConfigComponent + ], + bootstrap: [], + imports: [ + CommonModule, + FormsModule, + MatBottomSheetModule, + MatButtonModule, + MatCheckboxModule, + MatDialogModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatListModule, + MatSelectModule, + MatSlideToggleModule, + MatTabsModule, + MatToolbarModule, + MatTooltipModule, + MtxColorpickerModule, + ColorCompactModule + ], + providers: [ + ChartService, + ApiService, + { + provide: ErrorStateMatcher, + useClass: ShowOnDirtyErrorStateMatcher + }, + provideHttpClient(withInterceptorsFromDi()) + ] +}) export class SettingsModule { } diff --git a/Client/src/ngsw-config.json b/Client/src/ngsw-config.json new file mode 100644 index 00000000..01c879fa --- /dev/null +++ b/Client/src/ngsw-config.json @@ -0,0 +1,44 @@ +{ + "version": "YYYY.MM.DD", + "index": "/index.html", + "assetGroups": [ + { + "name": "app", + "installMode": "prefetch", + "resources": { + "files": [ + "/favicon.ico", + "/index.html", + "/*.css", + "/*.js" + ] + } + }, + { + "name": "assets", + "installMode": "lazy", + "updateMode": "prefetch", + "resources": { + "files": [ + "/assets/**", + "/*.(png|jpg|jpeg|svg)" + ] + } + } + ], + "dataGroups": [ + { + "name": "reference-data", + "urls": [ + "https://stock-charts-api.azurewebsites.net/indicators", + "https://localhost:44392/indicators" + ], + "cacheConfig": { + "strategy": "performance", + "maxSize": 10, + "maxAge": "1h", + "timeout": "10s" + } + } + ] +} diff --git a/Server/WebApi/Controllers/MainController.cs b/Server/WebApi/Controllers/MainController.cs index 213bfbd7..b119c9d1 100644 --- a/Server/WebApi/Controllers/MainController.cs +++ b/Server/WebApi/Controllers/MainController.cs @@ -24,7 +24,13 @@ public async Task GetQuotes() [HttpGet("indicators")] public IActionResult GetIndicators() - => Ok(Metadata.IndicatorList($"{Request.Scheme}://{Request.Host}")); + { + Response.Headers.CacheControl = "public, max-age=3600"; // 1 hour TTL + Response.Headers.ETag = "YYYY.MM.DD"; // only changes with deployment + Response.Headers.LastModified = DateTime.UtcNow.ToString("R"); + + return Ok(Metadata.IndicatorList($"{Request.Scheme}://{Request.Host}")); + } //////////////////////////////////////////