Makes the webpack build use relative paths to allow for deploying on web subdirectories
Some checks are pending
build-docker / Build Image (push) Waiting to run
Some checks are pending
build-docker / Build Image (push) Waiting to run
This commit is contained in:
parent
f77bcbadb7
commit
ea8c3bf602
10 changed files with 74 additions and 36 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import largeIcon from './icons/icons-large.mjs';
|
||||
import smallIcon from './icons/icons-small.mjs';
|
||||
import hourlyIcon from './icons/icons-hourly.mjs';
|
||||
import { withBasePath } from './utils/base-path.mjs';
|
||||
|
||||
const getWeatherGovTokenFromWmoCode = (code) => {
|
||||
switch (Number(code)) {
|
||||
|
|
@ -44,7 +45,7 @@ const getWeatherGovTokenFromWmoCode = (code) => {
|
|||
}
|
||||
};
|
||||
|
||||
const buildSyntheticIconUrl = (code, isDaytime = true) => `/icons/land/${isDaytime ? 'day' : 'night'}/${getWeatherGovTokenFromWmoCode(code)}`;
|
||||
const buildSyntheticIconUrl = (code, isDaytime = true) => withBasePath(`icons/land/${isDaytime ? 'day' : 'night'}/${getWeatherGovTokenFromWmoCode(code)}`);
|
||||
|
||||
const getLargeIconFromWmoCode = (code, isDaytime = true) => largeIcon(buildSyntheticIconUrl(code, isDaytime), !isDaytime);
|
||||
const getSmallIconFromWmoCode = (code, isDaytime = true) => smallIcon(buildSyntheticIconUrl(code, isDaytime), !isDaytime);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import STATUS from './status.mjs';
|
|||
import WeatherDisplay from './weatherdisplay.mjs';
|
||||
import { registerDisplay } from './navigation.mjs';
|
||||
import { debugFlag } from './utils/debug.mjs';
|
||||
import { withBasePath } from './utils/base-path.mjs';
|
||||
|
||||
const STORIES_PER_PAGE = 2;
|
||||
const PAGE_DURATION_MS = 9000;
|
||||
|
|
@ -17,7 +18,7 @@ class LinuxNews extends WeatherDisplay {
|
|||
if (!super.getData(weatherParameters, refresh)) return;
|
||||
|
||||
try {
|
||||
const response = await safeJson('/api/linux-news', {
|
||||
const response = await safeJson(withBasePath('api/linux-news'), {
|
||||
retryCount: 0,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import STATUS from './status.mjs';
|
|||
import WeatherDisplay from './weatherdisplay.mjs';
|
||||
import { registerDisplay } from './navigation.mjs';
|
||||
import { debugFlag } from './utils/debug.mjs';
|
||||
import { withBasePath } from './utils/base-path.mjs';
|
||||
|
||||
const LINES_PER_PAGE = 4;
|
||||
const PAGE_DURATION_MS = 7000;
|
||||
|
|
@ -19,7 +20,7 @@ class ServerObservations extends WeatherDisplay {
|
|||
|
||||
try {
|
||||
// Fetch server info from the API
|
||||
const response = await safeJson('/api/server-info', {
|
||||
const response = await safeJson(withBasePath('api/server-info'), {
|
||||
retryCount: 0,
|
||||
});
|
||||
|
||||
|
|
|
|||
25
server/scripts/modules/utils/base-path.mjs
Normal file
25
server/scripts/modules/utils/base-path.mjs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
const normalizeBasePath = (pathname) => {
|
||||
if (!pathname) return '/';
|
||||
if (pathname.endsWith('/index.html')) {
|
||||
const trimmed = pathname.slice(0, -'index.html'.length);
|
||||
return trimmed.endsWith('/') ? trimmed : `${trimmed}/`;
|
||||
}
|
||||
if (pathname.endsWith('/')) return pathname;
|
||||
const lastSlash = pathname.lastIndexOf('/');
|
||||
if (lastSlash === -1) return '/';
|
||||
return `${pathname.slice(0, lastSlash + 1)}`;
|
||||
};
|
||||
|
||||
const getBasePath = () => normalizeBasePath(window.location.pathname);
|
||||
|
||||
const withBasePath = (relativePath = '') => {
|
||||
const sanitizedPath = relativePath.replace(/^\/+/, '');
|
||||
const basePath = getBasePath();
|
||||
if (basePath === '/') return `/${sanitizedPath}`;
|
||||
return `${basePath}${sanitizedPath}`;
|
||||
};
|
||||
|
||||
export {
|
||||
getBasePath,
|
||||
withBasePath,
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { rewriteUrl } from './url-rewrite.mjs';
|
||||
import { withBasePath } from './base-path.mjs';
|
||||
|
||||
// Clear cache utility for client-side use
|
||||
const clearCacheEntry = async (url, baseUrl = '') => {
|
||||
|
|
@ -15,7 +16,7 @@ const clearCacheEntry = async (url, baseUrl = '') => {
|
|||
}
|
||||
|
||||
// Call the cache clear endpoint
|
||||
const fetchUrl = baseUrl ? `${baseUrl}/cache${cachePath}` : `/cache${cachePath}`;
|
||||
const fetchUrl = baseUrl ? `${baseUrl}/cache${cachePath}` : withBasePath(`cache${cachePath}`);
|
||||
const response = await fetch(fetchUrl, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// Data loader utility for fetching JSON data with cache-busting
|
||||
|
||||
import { withBasePath } from './base-path.mjs';
|
||||
|
||||
let dataCache = {};
|
||||
|
||||
// Load data with version-based cache busting
|
||||
|
|
@ -9,7 +11,7 @@ const loadData = async (dataType, version = '') => {
|
|||
}
|
||||
|
||||
try {
|
||||
const url = `/data/${dataType}.json${version ? `?_=${version}` : ''}`;
|
||||
const url = withBasePath(`data/${dataType}.json${version ? `?_=${version}` : ''}`);
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@ import { loadData } from './data-loader.mjs';
|
|||
import { getSmallIconFromWmoCode } from '../icons.mjs';
|
||||
import { getOpenMeteoObservationSnapshot } from './weather.mjs';
|
||||
import { temperature } from './units.mjs';
|
||||
import { withBasePath } from './base-path.mjs';
|
||||
|
||||
const getBaseMapUrl = () => (window.WS4KP_SERVER_AVAILABLE
|
||||
? '/arcgis-server/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}'
|
||||
? withBasePath('arcgis-server/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}')
|
||||
: 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}');
|
||||
const getBoundaryMapUrl = () => (window.WS4KP_SERVER_AVAILABLE
|
||||
? '/arcgis-services/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}'
|
||||
? withBasePath('arcgis-services/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}')
|
||||
: 'https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}');
|
||||
const DEFAULT_MAX_NEARBY_MARKERS = 7;
|
||||
const MIN_CITY_DISTANCE_METERS = 25000;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
import { safeJson } from './fetch.mjs';
|
||||
import { debugFlag } from './debug.mjs';
|
||||
import { withBasePath } from './base-path.mjs';
|
||||
|
||||
/**
|
||||
* Parse MapClick date format to JavaScript Date
|
||||
|
|
@ -178,7 +179,7 @@ const convertMapClickIcon = (weatherImage) => {
|
|||
return null;
|
||||
}
|
||||
|
||||
return `/icons/land/${timeOfDay}/${condition}?size=medium`;
|
||||
return withBasePath(`icons/land/${timeOfDay}/${condition}?size=medium`);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
import { withBasePath } from './base-path.mjs';
|
||||
|
||||
const THEME_STORAGE_KEY = 'settings-theme-select';
|
||||
const DEFAULT_THEME = 'default';
|
||||
|
||||
const BUILTIN_ASSETS = {
|
||||
background1: '../images/backgrounds/1.png',
|
||||
background1Chart: '../images/backgrounds/1-chart.png',
|
||||
background2: '../images/backgrounds/2.png',
|
||||
background3: '../images/backgrounds/3.png',
|
||||
background4: '../images/backgrounds/4.png',
|
||||
background5: '../images/backgrounds/5.png',
|
||||
background1: 'images/backgrounds/1.png',
|
||||
background1Chart: 'images/backgrounds/1-chart.png',
|
||||
background2: 'images/backgrounds/2.png',
|
||||
background3: 'images/backgrounds/3.png',
|
||||
background4: 'images/backgrounds/4.png',
|
||||
background5: 'images/backgrounds/5.png',
|
||||
logoCorner: 'images/logos/logo-corner.png',
|
||||
};
|
||||
|
||||
|
|
@ -20,33 +23,33 @@ const getStoredTheme = () => {
|
|||
|
||||
const getThemeAssetUrl = (themeName, assetKey) => {
|
||||
if (themeName === DEFAULT_THEME) {
|
||||
return BUILTIN_ASSETS[assetKey];
|
||||
return withBasePath(BUILTIN_ASSETS[assetKey]);
|
||||
}
|
||||
|
||||
const themeAssetAvailability = getThemeAssets()[themeName] ?? {};
|
||||
if (!themeAssetAvailability[assetKey]) {
|
||||
return BUILTIN_ASSETS[assetKey];
|
||||
return withBasePath(BUILTIN_ASSETS[assetKey]);
|
||||
}
|
||||
|
||||
switch (assetKey) {
|
||||
case 'background1':
|
||||
return `../themes/${themeName}/1.png`;
|
||||
return withBasePath(`themes/${themeName}/1.png`);
|
||||
case 'background1Chart':
|
||||
return `../themes/${themeName}/1-chart.png`;
|
||||
return withBasePath(`themes/${themeName}/1-chart.png`);
|
||||
case 'background2':
|
||||
return `../themes/${themeName}/2.png`;
|
||||
return withBasePath(`themes/${themeName}/2.png`);
|
||||
case 'background3':
|
||||
return `../themes/${themeName}/3.png`;
|
||||
return withBasePath(`themes/${themeName}/3.png`);
|
||||
case 'background4':
|
||||
return `../themes/${themeName}/4.png`;
|
||||
return withBasePath(`themes/${themeName}/4.png`);
|
||||
case 'background5':
|
||||
return `../themes/${themeName}/5.png`;
|
||||
return withBasePath(`themes/${themeName}/5.png`);
|
||||
case 'logoCorner':
|
||||
return `themes/${themeName}/logo-corner.png`;
|
||||
return withBasePath(`themes/${themeName}/logo-corner.png`);
|
||||
default:
|
||||
return BUILTIN_ASSETS[assetKey];
|
||||
}
|
||||
};
|
||||
return withBasePath(BUILTIN_ASSETS[assetKey]);
|
||||
}
|
||||
};
|
||||
|
||||
const applyTheme = (themeName) => {
|
||||
const selectedTheme = getAvailableThemes().includes(themeName) ? themeName : DEFAULT_THEME;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
// rewrite URLs to use local proxy server
|
||||
import { withBasePath } from './base-path.mjs';
|
||||
|
||||
const rewriteUrl = (_url) => {
|
||||
if (!_url) {
|
||||
throw new Error(`rewriteUrl called with invalid argument: '${_url}' (${typeof _url})`);
|
||||
|
|
@ -25,44 +27,44 @@ const rewriteUrl = (_url) => {
|
|||
if (url.origin === 'https://api.weather.gov') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/api${url.pathname}`;
|
||||
url.pathname = withBasePath(`api${url.pathname}`);
|
||||
} else if (url.origin === 'https://forecast.weather.gov') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/forecast${url.pathname}`;
|
||||
url.pathname = withBasePath(`forecast${url.pathname}`);
|
||||
} else if (url.origin === 'https://www.spc.noaa.gov') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/spc${url.pathname}`;
|
||||
url.pathname = withBasePath(`spc${url.pathname}`);
|
||||
} else if (url.origin === 'https://radar.weather.gov') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/radar${url.pathname}`;
|
||||
url.pathname = withBasePath(`radar${url.pathname}`);
|
||||
} else if (url.origin === 'https://mesonet.agron.iastate.edu') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/mesonet${url.pathname}`;
|
||||
url.pathname = withBasePath(`mesonet${url.pathname}`);
|
||||
} else if (url.origin === 'https://api.open-meteo.com') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/open-meteo${url.pathname}`;
|
||||
url.pathname = withBasePath(`open-meteo${url.pathname}`);
|
||||
} else if (url.origin === 'https://api.rainviewer.com') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/rainviewer${url.pathname}`;
|
||||
url.pathname = withBasePath(`rainviewer${url.pathname}`);
|
||||
} else if (url.origin === 'https://server.arcgisonline.com') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/arcgis-server${url.pathname}`;
|
||||
url.pathname = withBasePath(`arcgis-server${url.pathname}`);
|
||||
} else if (url.origin === 'https://services.arcgisonline.com') {
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/arcgis-services${url.pathname}`;
|
||||
url.pathname = withBasePath(`arcgis-services${url.pathname}`);
|
||||
} else if (typeof OVERRIDES !== 'undefined' && OVERRIDES?.RADAR_HOST && url.origin === `https://${OVERRIDES.RADAR_HOST}`) {
|
||||
// Handle override radar host
|
||||
url.protocol = window.location.protocol;
|
||||
url.host = window.location.host;
|
||||
url.pathname = `/mesonet${url.pathname}`;
|
||||
url.pathname = withBasePath(`mesonet${url.pathname}`);
|
||||
}
|
||||
|
||||
return url;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue