From 2303625a8a0eed80a5bb799ebbe3084c1bb1ce81 Mon Sep 17 00:00:00 2001 From: Marc Schmidt Date: Sun, 7 Jul 2024 14:39:19 +0200 Subject: [PATCH] fix: update button is never appearing in prod --- Dockerfile | 1 - package.json | 3 + pnpm-lock.yaml | 22 ++++- src/client/pnpm-lock.yaml | 8 +- .../player-events.component.html | 2 +- .../player-events/player-events.component.ts | 2 - .../src/app/environments/environment.prod.ts | 4 +- src/client/src/app/services/update.service.ts | 12 +-- src/client/src/index.html | 5 +- src/scripts/add-migration.js | 2 +- src/scripts/docker-build-inttest.js | 2 +- src/scripts/docker-build.js | 31 ++++--- src/scripts/docker-push.js | 2 +- src/scripts/remove-migration.js | 3 +- src/scripts/utils.js | 83 +++++++++++++++++++ src/scripts/vars.js | 24 ------ 16 files changed, 140 insertions(+), 66 deletions(-) create mode 100644 src/scripts/utils.js delete mode 100644 src/scripts/vars.js diff --git a/Dockerfile b/Dockerfile index 44aa199..ec61065 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,6 @@ ENV WEBPUSH__PRIVATEKEY= COPY src/server/host/bin/Release/publish . COPY src/client/dist/minigolf-friday/browser ./wwwroot/ -RUN sed -i "s/\$VERSION/$BUILDTIME/g" wwwroot/index.html HEALTHCHECK CMD wget --no-verbose --tries=1 --spider http://localhost/healthz || exit 1 diff --git a/package.json b/package.json index 9f6ede1..a9b45a2 100644 --- a/package.json +++ b/package.json @@ -15,5 +15,8 @@ "docker:build:inttest": "node src/scripts/docker-build-inttest.js", "docker:push": "node src/scripts/docker-push.js", "test:integration": "dotnet test test/MinigolfFriday.IntegrationTests/MinigolfFriday.IntegrationTests.csproj" + }, + "devDependencies": { + "@types/node": "^20.14.10" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b60ae1..4575986 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,4 +6,24 @@ settings: importers: - .: {} + .: + devDependencies: + '@types/node': + specifier: ^20.14.10 + version: 20.14.10 + +packages: + + '@types/node@20.14.10': + resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + +snapshots: + + '@types/node@20.14.10': + dependencies: + undici-types: 5.26.5 + + undici-types@5.26.5: {} diff --git a/src/client/pnpm-lock.yaml b/src/client/pnpm-lock.yaml index 7f0348f..6be4ced 100644 --- a/src/client/pnpm-lock.yaml +++ b/src/client/pnpm-lock.yaml @@ -3402,10 +3402,6 @@ packages: engines: {node: '>=12'} hasBin: true - escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -9983,8 +9979,6 @@ snapshots: '@esbuild/win32-ia32': 0.21.3 '@esbuild/win32-x64': 0.21.3 - escalade@3.1.1: {} - escalade@3.1.2: {} escape-html@1.0.3: {} @@ -13003,7 +12997,7 @@ snapshots: update-browserslist-db@1.0.13(browserslist@4.22.3): dependencies: browserslist: 4.22.3 - escalade: 3.1.1 + escalade: 3.1.2 picocolors: 1.0.0 update-browserslist-db@1.0.16(browserslist@4.23.1): diff --git a/src/client/src/app/components/player-events/player-events.component.html b/src/client/src/app/components/player-events/player-events.component.html index 4aecf8b..d031cd4 100644 --- a/src/client/src/app/components/player-events/player-events.component.html +++ b/src/client/src/app/components/player-events/player-events.component.html @@ -14,7 +14,7 @@

{{ translations.playerEvents_greetings() | interpolate: { name: user.alias } > -} @else { +} @else if (user()?.roles?.includes('player')) {

{{ translations.playerEvents_currentEvents() }}

diff --git a/src/client/src/app/components/player-events/player-events.component.ts b/src/client/src/app/components/player-events/player-events.component.ts index a8c521a..a634963 100644 --- a/src/client/src/app/components/player-events/player-events.component.ts +++ b/src/client/src/app/components/player-events/player-events.component.ts @@ -2,7 +2,6 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { RouterLink } from '@angular/router'; -import { Store } from '@ngrx/store'; import { MessagesModule } from 'primeng/messages'; import { ProgressSpinnerModule } from 'primeng/progressspinner'; import { map, timer } from 'rxjs'; @@ -28,7 +27,6 @@ const dayMillis = 24 * 60 * 60 * 1000; changeDetection: ChangeDetectionStrategy.OnPush, }) export class PlayerEventsComponent { - private readonly _store = inject(Store); private readonly _translateService = inject(TranslateService); protected readonly translations = this._translateService.translations; diff --git a/src/client/src/app/environments/environment.prod.ts b/src/client/src/app/environments/environment.prod.ts index 9d28b5f..7e91643 100644 --- a/src/client/src/app/environments/environment.prod.ts +++ b/src/client/src/app/environments/environment.prod.ts @@ -1,9 +1,7 @@ import { Environment } from './environment.type'; -const minigolfFriday: { version: string } = (window as any).minigolfFriday; - export const environment: Environment = { getProviders: () => [], authenticationRequired: true, - ...minigolfFriday, + version: (document.head.querySelector('meta[name="version"]') as HTMLMetaElement)?.content ?? '', }; diff --git a/src/client/src/app/services/update.service.ts b/src/client/src/app/services/update.service.ts index 1d0530f..489b912 100644 --- a/src/client/src/app/services/update.service.ts +++ b/src/client/src/app/services/update.service.ts @@ -1,7 +1,7 @@ import { inject, Injectable } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { SwUpdate } from '@angular/service-worker'; -import { merge, filter, map } from 'rxjs'; +import { merge, filter, map, debounceTime } from 'rxjs'; import { RealtimeEventsService } from './realtime-events.service'; import { onDocumentVisibilityChange$ } from '../utils/event.utils'; @@ -24,10 +24,12 @@ export class UpdateService { merge( onDocumentVisibilityChange$().pipe(filter(isVisible => isVisible)), this._realtimeEventsService.onReconnected$ - ).subscribe(() => { - console.info('Checking for updates...'); - this._swUpdate.checkForUpdate().then(x => console.info('Update check result:', x)); - }); + ) + .pipe(debounceTime(1000)) + .subscribe(() => { + console.info('Checking for updates...'); + this._swUpdate.checkForUpdate().then(x => console.info('Update check result:', x)); + }); this._swUpdate.unrecoverable.subscribe(() => location.reload()); } } diff --git a/src/client/src/index.html b/src/client/src/index.html index c8a3a6d..42af4a4 100644 --- a/src/client/src/index.html +++ b/src/client/src/index.html @@ -9,6 +9,7 @@ content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" /> + @@ -40,10 +41,6 @@ if (theme === 'dark') { document.body.classList.add('dark'); } - - window.minigolfFriday = { - version: '$VERSION', - }; diff --git a/src/scripts/add-migration.js b/src/scripts/add-migration.js index ba9e0ac..de4e624 100644 --- a/src/scripts/add-migration.js +++ b/src/scripts/add-migration.js @@ -1,6 +1,6 @@ import { spawnSync } from "child_process"; import { argv } from "process"; -import { repoRootDir } from "./vars.js"; +import { repoRootDir } from "./utils.js"; import path from "path"; const name = argv[2]; diff --git a/src/scripts/docker-build-inttest.js b/src/scripts/docker-build-inttest.js index 1594848..0971d75 100644 --- a/src/scripts/docker-build-inttest.js +++ b/src/scripts/docker-build-inttest.js @@ -1,5 +1,5 @@ import { spawnSync } from "child_process"; -import { repository, imageName, repoRootDir, getArg, getVersionTag } from "./vars.js"; +import { repository, imageName, repoRootDir, getArg, getVersionTag } from "./utils.js"; const configuration = getArg("--configuration", "-c") ?? "Release"; diff --git a/src/scripts/docker-build.js b/src/scripts/docker-build.js index 3af0272..962ddb3 100644 --- a/src/scripts/docker-build.js +++ b/src/scripts/docker-build.js @@ -1,15 +1,20 @@ import { spawnSync } from "child_process"; -import { repository, imageName, repoRootDir, getVersionTag } from "./vars.js"; +import { repository, imageName, repoRootDir, getVersionTag, setIndexHtmlVersion } from "./utils.js"; -const buildtime = getVersionTag(); -spawnSync( - "docker", - [ - "build", - `-t=${repository}/${imageName}:latest`, - `-t=${repository}/${imageName}:${buildtime}`, - `--build-arg=BUILDTIME=${buildtime}`, - ".", - ], - { cwd: repoRootDir, stdio: "inherit" } -); +(async () => { + const buildtime = getVersionTag(); + + await setIndexHtmlVersion("src/client/dist/minigolf-friday/browser", buildtime); + + spawnSync( + "docker", + [ + "build", + `-t=${repository}/${imageName}:latest`, + `-t=${repository}/${imageName}:${buildtime}`, + `--build-arg=BUILDTIME=${buildtime}`, + ".", + ], + { cwd: repoRootDir, stdio: "inherit" } + ); +})(); diff --git a/src/scripts/docker-push.js b/src/scripts/docker-push.js index d4dfb60..97d1084 100644 --- a/src/scripts/docker-push.js +++ b/src/scripts/docker-push.js @@ -1,5 +1,5 @@ import { spawnSync } from "child_process"; -import { repository, imageName, repoRootDir, getVersionTag } from "./vars.js"; +import { repository, imageName, repoRootDir, getVersionTag } from "./utils.js"; import { appendFileSync } from "fs"; const inspectResult = spawnSync( diff --git a/src/scripts/remove-migration.js b/src/scripts/remove-migration.js index 75f0e63..e5576e3 100644 --- a/src/scripts/remove-migration.js +++ b/src/scripts/remove-migration.js @@ -1,6 +1,5 @@ import { spawnSync } from "child_process"; -import { argv } from "process"; -import { repoRootDir } from "./vars.js"; +import { repoRootDir } from "./utils.js"; import path from "path"; const buildResult = spawnSync("dotnet", ["build"], { diff --git a/src/scripts/utils.js b/src/scripts/utils.js new file mode 100644 index 0000000..6346a91 --- /dev/null +++ b/src/scripts/utils.js @@ -0,0 +1,83 @@ +import crypt from "crypto"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; +import { argv } from "process"; + +export const repoRootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); +export const imageName = "minigolf-friday"; +export const repository = "masch0212"; + +export function getVersionTag() { + const dateIso = new Date().toISOString(); + return dateIso.replace(/[-T:.Z]/g, (x) => (x === "T" ? "-" : "")).substring(0, 15); +} + +export function getArg(longName, shortName) { + const longIndex = argv.indexOf(longName); + if (longIndex > -1) { + return argv[longIndex + 1]; + } + const shortIndex = argv.indexOf(shortName); + if (shortIndex > -1) { + return argv[shortIndex + 1]; + } + return null; +} + +export async function setIndexHtmlVersion(distDir, version) { + const indexHtmlPath = path.resolve(distDir, "index.html"); + if (!fs.existsSync(indexHtmlPath)) { + throw new Error(`File ${indexHtmlPath} not found`); + } + + let indexHtml = fs.readFileSync(indexHtmlPath, "utf8"); + indexHtml = indexHtml.replace( + //, + `` + ); + fs.writeFileSync(indexHtmlPath, indexHtml); + await rebuildNgswFileHash(distDir, "/index.html"); +} + +function rebuildNgswFileHash(distDir, file) { + const ngswPath = path.resolve(distDir, "ngsw.json"); + if (!fs.existsSync(ngswPath)) { + console.error(`File ${ngswPath} not found`); + process.exit(1); + } + + const ngsw = JSON.parse(fs.readFileSync(ngswPath, "utf8")); + if (!ngsw.hashTable[file]) { + console.error(`File ${file} not found in ngsw.json`); + process.exit(1); + } + + const filePath = path.resolve(distDir, file.replace(/^\//, "")); + if (!fs.existsSync(filePath)) { + console.error(`File ${filePath} not found`); + process.exit(1); + } + + const fd = fs.createReadStream(filePath); + const hash = crypt.createHash("sha1"); + hash.setEncoding("hex"); + + return new Promise((resolve, reject) => { + fd.on("end", () => { + hash.end(); + + try { + console.log(`Old hash for ${file}: ${ngsw.hashTable[file]}`); + ngsw.hashTable[file] = hash.read(); + console.log(`New hash for ${file}: ${ngsw.hashTable[file]}`); + fs.writeFileSync(ngswPath, JSON.stringify(ngsw, null, 2)); + resolve(); + } catch (error) { + reject(error); + } + }); + + fd.pipe(hash); + }); +} diff --git a/src/scripts/vars.js b/src/scripts/vars.js deleted file mode 100644 index 2a4ab49..0000000 --- a/src/scripts/vars.js +++ /dev/null @@ -1,24 +0,0 @@ -import path from "path"; -import { fileURLToPath } from "url"; -import { argv } from "process"; - -export const repoRootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -export const imageName = "minigolf-friday"; -export const repository = "masch0212"; - -export function getVersionTag() { - const dateIso = new Date().toISOString(); - return dateIso.replace(/[-T:.Z]/g, (x) => (x === "T" ? "-" : "")).substring(0, 15); -} - -export function getArg(longName, shortName) { - const longIndex = argv.indexOf(longName); - if (longIndex > -1) { - return argv[longIndex + 1]; - } - const shortIndex = argv.indexOf(shortName); - if (shortIndex > -1) { - return argv[shortIndex + 1]; - } - return null; -}