From 480c5c1584c43c0f2d1ad82054e33b62a442a730 Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Thu, 14 Apr 2022 13:49:54 +0200 Subject: [PATCH 01/15] update SDK docs with new style location --- doc/SDK.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/SDK.md b/doc/SDK.md index 8ce0b304..54e37cca 100644 --- a/doc/SDK.md +++ b/doc/SDK.md @@ -47,7 +47,8 @@ const assetPaths = { wasmBundle: olmJsPath } }; -import "hydrogen-view-sdk/style.css"; +import "hydrogen-view-sdk/theme-element-light.css"; +// OR import "hydrogen-view-sdk/theme-element-dark.css"; async function main() { const app = document.querySelector('#app')! From 2cfcd4653f7a4b191f96c188b2ced0293421f396 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 20 Apr 2022 12:00:33 +0530 Subject: [PATCH 02/15] Use named params --- src/platform/web/Platform.js | 2 +- src/platform/web/index.html | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 984bc45c..1c630aed 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -126,7 +126,7 @@ function adaptUIOnVisualViewportResize(container) { } export class Platform { - constructor(container, assetPaths, config, options = null, cryptoExtras = null) { + constructor({ container, assetPaths, config, options = null, cryptoExtras = null }) { this._container = container; this._assetPaths = assetPaths; this._config = config; diff --git a/src/platform/web/index.html b/src/platform/web/index.html index 5950d89f..ed0e8eb0 100644 --- a/src/platform/web/index.html +++ b/src/platform/web/index.html @@ -22,11 +22,12 @@ if (import.meta.env.PROD) { assetPaths.serviceWorker = "sw.js"; } - const platform = new Platform( - document.body, + const platform = new Platform({ + container: document.body, assetPaths, - JSON.parse(configJSON), - {development: import.meta.env.DEV} + config: JSON.parse(configJSON), + options: {development: import.meta.env.DEV} + } ); main(platform); From 6cd3c8ee2bfab6498f260eb5e91cacb16c11688a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 20 Apr 2022 12:25:23 +0530 Subject: [PATCH 03/15] Read config from URL --- src/platform/web/Platform.js | 19 +++++++++++++++++-- src/platform/web/index.html | 7 +++---- src/platform/web/main.js | 1 + vite.common-config.js | 1 + 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 1c630aed..92608d75 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -126,10 +126,11 @@ function adaptUIOnVisualViewportResize(container) { } export class Platform { - constructor({ container, assetPaths, config, options = null, cryptoExtras = null }) { + constructor({ container, assetPaths, config, configURL, options = null, cryptoExtras = null }) { this._container = container; this._assetPaths = assetPaths; this._config = config; + this._configURL = configURL; this.settingsStorage = new SettingsStorage("hydrogen_setting_v1_"); this.clock = new Clock(); this.encoding = new Encoding(); @@ -142,7 +143,7 @@ export class Platform { this._serviceWorkerHandler = new ServiceWorkerHandler(); this._serviceWorkerHandler.registerAndStart(assetPaths.serviceWorker); } - this.notificationService = new NotificationService(this._serviceWorkerHandler, config.push); + this.notificationService = null; // Only try to use crypto when olm is provided if(this._assetPaths.olm) { this.crypto = new Crypto(cryptoExtras); @@ -165,6 +166,20 @@ export class Platform { this._workerPromise = undefined; } + async init() { + if (!this._config) { + if (!this._configURL) { + throw new Error("Neither config nor configURL was provided!"); + } + const {body}= await this.request(this._configURL, {method: "GET", format: "json"}).response(); + this._config = body; + } + this._notificationService = new NotificationService( + this._serviceWorkerHandler, + this._config.push + ); + } + _createLogger(isDevelopment) { // Make sure that loginToken does not end up in the logs const transformer = (item) => { diff --git a/src/platform/web/index.html b/src/platform/web/index.html index ed0e8eb0..16418699 100644 --- a/src/platform/web/index.html +++ b/src/platform/web/index.html @@ -17,7 +17,7 @@ diff --git a/src/platform/web/main.js b/src/platform/web/main.js index 1729c17c..edc2cf14 100644 --- a/src/platform/web/main.js +++ b/src/platform/web/main.js @@ -32,6 +32,7 @@ export async function main(platform) { // const recorder = new RecordRequester(createFetchRequest(clock.createTimeout)); // const request = recorder.request; // window.getBrawlFetchLog = () => recorder.log(); + await platform.init(); const navigation = createNavigation(); platform.setNavigation(navigation); const urlRouter = createRouter({navigation, history: platform.history}); diff --git a/vite.common-config.js b/vite.common-config.js index f5a90154..8a82a9da 100644 --- a/vite.common-config.js +++ b/vite.common-config.js @@ -31,6 +31,7 @@ const commonOptions = { assetsInlineLimit: 0, polyfillModulePreload: false, }, + assetsInclude: ['**/config.json'], define: { DEFINE_VERSION: JSON.stringify(version), DEFINE_GLOBAL_HASH: JSON.stringify(null), From 5f8a171c2c706a884321c16f9798874fc1bf364b Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 20 Apr 2022 11:55:48 -0500 Subject: [PATCH 04/15] Fix asset build throwing and swallowing errors (#721) - Fix `svg-colorizer` throwing errors with Windows file paths - Fix `css-url-parser` swallowing errors because it was `async` - Fail SDK build script (`yarn build:sdk`, `build.sh`) overall when some commands are failing --- scripts/postcss/css-url-processor.js | 2 +- scripts/postcss/svg-colorizer.js | 2 +- scripts/sdk/build.sh | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/postcss/css-url-processor.js b/scripts/postcss/css-url-processor.js index 3ae7c60d..f58818f1 100644 --- a/scripts/postcss/css-url-processor.js +++ b/scripts/postcss/css-url-processor.js @@ -39,7 +39,7 @@ function colorsFromURL(url, colorMap) { function processURL(decl, replacer, colorMap) { const value = decl.value; const parsed = valueParser(value); - parsed.walk(async node => { + parsed.walk(node => { if (node.type !== "function" || node.value !== "url") { return; } diff --git a/scripts/postcss/svg-colorizer.js b/scripts/postcss/svg-colorizer.js index 95355ea8..06b7b14b 100644 --- a/scripts/postcss/svg-colorizer.js +++ b/scripts/postcss/svg-colorizer.js @@ -37,7 +37,7 @@ module.exports.buildColorizedSVG = function (svgLocation, primaryColor, secondar if (svgCode === coloredSVGCode) { throw new Error("svg-colorizer made no color replacements! The input svg should only contain colors #ff00ff (primary, case-sensitive) and #00ffff (secondary, case-sensitive)."); } - const fileName = svgLocation.match(/.+\/(.+\.svg)/)[1]; + const fileName = svgLocation.match(/.+[/\\](.+\.svg)/)[1]; const outputName = `${fileName.substring(0, fileName.length - 4)}-${createHash(coloredSVGCode)}.svg`; const outputPath = path.resolve(__dirname, "../../.tmp"); try { diff --git a/scripts/sdk/build.sh b/scripts/sdk/build.sh index 2ac4be3a..ae3a794e 100755 --- a/scripts/sdk/build.sh +++ b/scripts/sdk/build.sh @@ -1,4 +1,8 @@ #!/bin/bash +# Exit whenever one of the commands fail with a non-zero exit code +set -e +set -o pipefail + rm -rf target yarn run vite build -c vite.sdk-assets-config.js yarn run vite build -c vite.sdk-lib-config.js From 468b7e15954df04bff84a99252fc6ced16aa5816 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 21 Apr 2022 12:52:42 +0530 Subject: [PATCH 05/15] Cache config.json --- src/platform/web/Platform.js | 2 +- src/platform/web/sw.js | 35 ++++++++++++++++++++++++++++++++++- vite.config.js | 5 +++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 92608d75..7d5126dc 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -171,7 +171,7 @@ export class Platform { if (!this._configURL) { throw new Error("Neither config nor configURL was provided!"); } - const {body}= await this.request(this._configURL, {method: "GET", format: "json"}).response(); + const {body}= await this.request(this._configURL, {method: "GET", format: "json", cache: true}).response(); this._config = body; } this._notificationService = new NotificationService( diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index c5f69438..e57634fc 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -75,7 +75,14 @@ self.addEventListener('fetch', (event) => { This has to do with xhr not being supported in service workers. */ if (event.request.method === "GET") { - event.respondWith(handleRequest(event.request)); + if (event.request.url.includes("config.json")) { + /** + * Use a different strategy for this file. + */ + event.respondWith(handleConfigRequest(event.request)); + } else { + event.respondWith(handleRequest(event.request)); + } } }); @@ -119,6 +126,32 @@ async function handleRequest(request) { } } +async function handleConfigRequest(request) { + const url = new URL(request.url); + // rewrite / to /index.html so it hits the cache + if (url.origin === baseURL.origin && url.pathname === baseURL.pathname) { + request = new Request(new URL("index.html", baseURL.href)); + } + let response = await readCache(request); + if (response) { + fetchAndUpdateConfig(request); + return response; + } + response = await fetchAndUpdateConfig(request); + return response; +} + +async function fetchAndUpdateConfig(request) { + const response = await fetch(request, { + signal: pendingFetchAbortController.signal, + headers: { + "Cache-Control": "no-cache", + }, + }); + updateCache(request, response.clone()); + return response; +} + async function updateCache(request, response) { // don't write error responses to the cache if (response.status >= 400) { diff --git a/vite.config.js b/vite.config.js index 4dd35af2..87e3d063 100644 --- a/vite.config.js +++ b/vite.config.js @@ -14,6 +14,11 @@ export default defineConfig(({mode}) => { outDir: "../../../target", minify: true, sourcemap: true, + rollupOptions: { + output: { + assetFileNames: (asset) => asset.name.includes("config.json") ? "assets/[name][extname]": "assets/[name].[hash][extname]", + }, + }, }, plugins: [ themeBuilder({ From 1cdc76f5a464871a50ca909a1eb4d126e5632703 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 21 Apr 2022 14:14:38 +0530 Subject: [PATCH 06/15] Use undefine instead of null --- src/platform/web/Platform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 7d5126dc..1c999598 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -143,7 +143,7 @@ export class Platform { this._serviceWorkerHandler = new ServiceWorkerHandler(); this._serviceWorkerHandler.registerAndStart(assetPaths.serviceWorker); } - this.notificationService = null; + this.notificationService = undefined; // Only try to use crypto when olm is provided if(this._assetPaths.olm) { this.crypto = new Crypto(cryptoExtras); From 4f239445816df107fb446ba3b46345a20e77cbb4 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 21 Apr 2022 14:17:47 +0530 Subject: [PATCH 07/15] Use named param in Legacy Platform --- src/platform/web/LegacyPlatform.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/web/LegacyPlatform.js b/src/platform/web/LegacyPlatform.js index 85632bf2..b8a6d7e7 100644 --- a/src/platform/web/LegacyPlatform.js +++ b/src/platform/web/LegacyPlatform.js @@ -19,6 +19,6 @@ import {hkdf} from "../../utils/crypto/hkdf"; import {Platform as ModernPlatform} from "./Platform.js"; -export function Platform(container, assetPaths, config, options = null) { - return new ModernPlatform(container, assetPaths, config, options, {aesjs, hkdf}); +export function Platform({ container, assetPaths, config, configURL, options = null }) { + return new ModernPlatform({ container, assetPaths, config, configURL, options, cryptoExtras: { aesjs, hkdf }}); } From b6e55ef59c263901421f8e53db23f301a91f0633 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 21 Apr 2022 14:46:55 +0530 Subject: [PATCH 08/15] Remove comment --- src/platform/web/sw.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index e57634fc..aaf56c4b 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -76,9 +76,6 @@ self.addEventListener('fetch', (event) => { */ if (event.request.method === "GET") { if (event.request.url.includes("config.json")) { - /** - * Use a different strategy for this file. - */ event.respondWith(handleConfigRequest(event.request)); } else { event.respondWith(handleRequest(event.request)); From 826835e518666d3fd7d09f4e944c98ee3650d369 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 22 Apr 2022 12:07:53 +0530 Subject: [PATCH 09/15] No need to rewrite to index.html --- src/platform/web/sw.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index aaf56c4b..91ae85c5 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -124,11 +124,6 @@ async function handleRequest(request) { } async function handleConfigRequest(request) { - const url = new URL(request.url); - // rewrite / to /index.html so it hits the cache - if (url.origin === baseURL.origin && url.pathname === baseURL.pathname) { - request = new Request(new URL("index.html", baseURL.href)); - } let response = await readCache(request); if (response) { fetchAndUpdateConfig(request); From c6691cf1cbd6fe69b617f445d1ed6a3fe297c216 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 22 Apr 2022 12:10:25 +0530 Subject: [PATCH 10/15] Simplify code --- src/platform/web/sw.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index 91ae85c5..2d43d1ee 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -125,12 +125,12 @@ async function handleRequest(request) { async function handleConfigRequest(request) { let response = await readCache(request); + const networkResponsePromise = fetchAndUpdateConfig(request); if (response) { - fetchAndUpdateConfig(request); return response; + } else { + return await networkResponsePromise; } - response = await fetchAndUpdateConfig(request); - return response; } async function fetchAndUpdateConfig(request) { From 5a94a2feba344029699705dd15f33891266b7b6c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 22 Apr 2022 12:22:30 +0530 Subject: [PATCH 11/15] Move handleConfigRequest inside handleRequest --- src/platform/web/sw.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index 2d43d1ee..a9a92979 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -75,11 +75,7 @@ self.addEventListener('fetch', (event) => { This has to do with xhr not being supported in service workers. */ if (event.request.method === "GET") { - if (event.request.url.includes("config.json")) { - event.respondWith(handleConfigRequest(event.request)); - } else { - event.respondWith(handleRequest(event.request)); - } + event.respondWith(handleRequest(event.request)); } }); @@ -96,8 +92,12 @@ function isCacheableThumbnail(url) { const baseURL = new URL(self.registration.scope); let pendingFetchAbortController = new AbortController(); + async function handleRequest(request) { try { + if (request.url.includes("config.json")) { + return handleConfigRequest(request); + } const url = new URL(request.url); // rewrite / to /index.html so it hits the cache if (url.origin === baseURL.origin && url.pathname === baseURL.pathname) { From 7a33c2e00d69f09979a3f668bff6e130441f5623 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 22 Apr 2022 12:26:29 +0530 Subject: [PATCH 12/15] await --- src/platform/web/sw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index a9a92979..49789804 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -96,7 +96,7 @@ let pendingFetchAbortController = new AbortController(); async function handleRequest(request) { try { if (request.url.includes("config.json")) { - return handleConfigRequest(request); + return await handleConfigRequest(request); } const url = new URL(request.url); // rewrite / to /index.html so it hits the cache From d8da1287804921bd785be8383b51827913b2c1d6 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 22 Apr 2022 14:34:16 +0530 Subject: [PATCH 13/15] remove await --- src/platform/web/sw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index 49789804..a9a92979 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -96,7 +96,7 @@ let pendingFetchAbortController = new AbortController(); async function handleRequest(request) { try { if (request.url.includes("config.json")) { - return await handleConfigRequest(request); + return handleConfigRequest(request); } const url = new URL(request.url); // rewrite / to /index.html so it hits the cache From 6c57c96cb9a7a3b77f4fd1c92723bfbbad59b860 Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Mon, 25 Apr 2022 12:07:28 +0200 Subject: [PATCH 14/15] add typing for text bindings in template view --- src/platform/web/ui/general/TemplateView.ts | 24 +++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/platform/web/ui/general/TemplateView.ts b/src/platform/web/ui/general/TemplateView.ts index ce593f75..a0e2079a 100644 --- a/src/platform/web/ui/general/TemplateView.ts +++ b/src/platform/web/ui/general/TemplateView.ts @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS, ClassNames, Child} from "./html"; +import { setAttribute, text, isChildren, classNames, TAG_NAMES, HTML_NS, ClassNames, Child as NonBoundChild} from "./html"; import {mountView} from "./utils"; import {BaseUpdateView, IObservableValue} from "./BaseUpdateView"; import {IMountArgs, ViewNode, IView} from "./types"; @@ -30,12 +30,15 @@ function objHasFns(obj: ClassNames): obj is { [className: string]: bool } export type RenderFn = (t: Builder, vm: T) => ViewNode; +type TextBinding = (T) => string | number | boolean | undefined | null; +type Child = NonBoundChild | TextBinding; +type Children = Child | Child[]; type EventHandler = ((event: Event) => void); type AttributeStaticValue = string | boolean; type AttributeBinding = (value: T) => AttributeStaticValue; export type AttrValue = AttributeStaticValue | AttributeBinding | EventHandler | ClassNames; export type Attributes = { [attribute: string]: AttrValue }; -type ElementFn = (attributes?: Attributes | Child | Child[], children?: Child | Child[]) => Element; +type ElementFn = (attributes?: Attributes | Children, children?: Children) => Element; export type Builder = TemplateBuilder & { [tagName in typeof TAG_NAMES[string][number]]: ElementFn }; /** @@ -195,15 +198,15 @@ export class TemplateBuilder { this._addAttributeBinding(node, "className", value => classNames(obj, value)); } - _addTextBinding(fn: (value: T) => string): Text { - const initialValue = fn(this._value); + _addTextBinding(fn: (value: T) => ReturnType>): Text { + const initialValue = fn(this._value)+""; const node = text(initialValue); let prevValue = initialValue; const binding = () => { - const newValue = fn(this._value); + const newValue = fn(this._value)+""; if (prevValue !== newValue) { prevValue = newValue; - node.textContent = newValue+""; + node.textContent = newValue; } }; @@ -242,7 +245,7 @@ export class TemplateBuilder { } } - _setNodeChildren(node: Element, children: Child | Child[]): void{ + _setNodeChildren(node: Element, children: Children): void{ if (!Array.isArray(children)) { children = [children]; } @@ -276,14 +279,17 @@ export class TemplateBuilder { return node; } - el(name: string, attributes?: Attributes | Child | Child[], children?: Child | Child[]): ViewNode { + el(name: string, attributes?: Attributes | Children, children?: Children): ViewNode { return this.elNS(HTML_NS, name, attributes, children); } - elNS(ns: string, name: string, attributes?: Attributes | Child | Child[], children?: Child | Child[]): ViewNode { + elNS(ns: string, name: string, attributesOrChildren?: Attributes | Children, children?: Children): ViewNode { + let attributes: Attributes | undefined; if (attributes !== undefined && isChildren(attributes)) { children = attributes; attributes = undefined; + } else { + attributes = attributesOrChildren as Attributes; } const node = document.createElementNS(ns, name); From ab893f63b5534cd40df096ef70f6a04456ec3f6d Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Mon, 25 Apr 2022 12:40:25 +0200 Subject: [PATCH 15/15] remove unneeded assignment --- src/platform/web/ui/general/TemplateView.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform/web/ui/general/TemplateView.ts b/src/platform/web/ui/general/TemplateView.ts index a0e2079a..7f7f4c13 100644 --- a/src/platform/web/ui/general/TemplateView.ts +++ b/src/platform/web/ui/general/TemplateView.ts @@ -287,7 +287,6 @@ export class TemplateBuilder { let attributes: Attributes | undefined; if (attributes !== undefined && isChildren(attributes)) { children = attributes; - attributes = undefined; } else { attributes = attributesOrChildren as Attributes; }