@nectary/theme-base
Advanced tools
| import { getThemeStore } from './global-theme-store'; | ||
| import { loadModuleWithFallback } from './shared/cdn-loader'; | ||
| import { loadCSSModuleWithFallback } from './shared/cdn-loader'; // separate function due to how CSS is allowed to be loaded in the browser | ||
| class GlobalThemeManagerImpl { | ||
@@ -65,3 +66,3 @@ static instance = null; | ||
| loadModule(cdnUrl, fallbackCdnUrl, version, modulePath) { | ||
| return loadModuleWithFallback({ | ||
| return loadCSSModuleWithFallback({ | ||
| cdnUrl, | ||
@@ -68,0 +69,0 @@ fallbackCdnUrl, |
@@ -9,2 +9,3 @@ interface LoadModuleOptions { | ||
| export declare const loadModuleWithFallback: <TModule = Record<string, any>>(options: LoadModuleOptions) => Promise<TModule>; | ||
| export declare const loadCSSModuleWithFallback: <TModule = Record<string, any>>(options: LoadModuleOptions) => Promise<TModule>; | ||
| export {}; |
@@ -17,2 +17,18 @@ const getImportPath = (cdnUrl, version, modulePath) => { | ||
| }; | ||
| const getCssImportPath = (cdnUrl, version, modulePath) => { | ||
| if (cdnUrl.length === 0) { | ||
| return null; | ||
| } | ||
| const host = new URL(cdnUrl).host; | ||
| if (host === 'esm.sh') { | ||
| if (version.length !== 0) { | ||
| return `${cdnUrl}@${version}/es2022/${modulePath}.css`; | ||
| } | ||
| return `${cdnUrl}/${modulePath}`; | ||
| } | ||
| if (version.length !== 0) { | ||
| return `${cdnUrl}/${version}/${modulePath}.css`; | ||
| } | ||
| return `${cdnUrl}/latest/${modulePath}.css`; | ||
| }; | ||
| const FALLBACK_DELAY_MS = 2000; | ||
@@ -53,2 +69,53 @@ export const loadModuleWithFallback = async options => { | ||
| } | ||
| }; | ||
| const fetchCSS = async url => { | ||
| const res = await fetch(url); | ||
| if (!res.ok) { | ||
| throw new Error(`CSS fetch failed: ${res.status} ${url}`); | ||
| } | ||
| const css = await res.text(); | ||
| return { | ||
| default: css | ||
| }; | ||
| }; | ||
| const loadCSSFromUrl = url => { | ||
| if (url.endsWith('.css')) { | ||
| return fetchCSS(url); | ||
| } | ||
| return import(/* webpackIgnore: true */url); | ||
| }; | ||
| export const loadCSSModuleWithFallback = async options => { | ||
| const { | ||
| cdnUrl, | ||
| fallbackCdnUrl, | ||
| version, | ||
| modulePath, | ||
| logPrefix = 'CDN' | ||
| } = options; | ||
| const importPath = getCssImportPath(cdnUrl, version, modulePath); | ||
| const fallbackImportPath = getCssImportPath(fallbackCdnUrl, version, modulePath); | ||
| const promises = [loadCSSFromUrl(importPath)]; | ||
| let timeoutId = null; | ||
| if (fallbackImportPath !== null) { | ||
| promises.push(new Promise(resolve => { | ||
| timeoutId = setTimeout(() => resolve(loadCSSFromUrl(fallbackImportPath)), FALLBACK_DELAY_MS); | ||
| })); | ||
| } | ||
| try { | ||
| const module = await Promise.any(promises); | ||
| if (timeoutId !== null) { | ||
| clearTimeout(timeoutId); | ||
| } | ||
| return module; | ||
| } catch (error) { | ||
| if (error instanceof AggregateError) { | ||
| console.error(`${logPrefix} primary load failed: ${importPath}`, error.errors[0]); | ||
| if (fallbackImportPath !== null) { | ||
| console.error(`${logPrefix} fallback load failed: ${fallbackImportPath}`, error.errors[1]); | ||
| } | ||
| } else { | ||
| console.error(`${logPrefix} failed to load module: ${importPath}`, error); | ||
| } | ||
| throw error; | ||
| } | ||
| }; |
+1
-1
| { | ||
| "name": "@nectary/theme-base", | ||
| "version": "1.11.0", | ||
| "version": "1.11.1", | ||
| "main": "index.css", | ||
@@ -5,0 +5,0 @@ "exports": { |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
128455
1.72%2199
3.19%2
Infinity%