Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions platform/app/.webpack/webpack.pwa.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const PUBLIC_DIR = path.join(__dirname, '../public');
const WATCH_IGNORED = /node_modules[\\/](?!@cornerstonejs(?:[\\/]|$))/;
// ~~ Env Vars
const HTML_TEMPLATE = process.env.HTML_TEMPLATE || 'index.html';
const PUBLIC_URL = process.env.PUBLIC_URL || '/';
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';

// proxy settings
Expand Down Expand Up @@ -69,7 +68,7 @@ module.exports = (env, argv) => {
output: {
path: DIST_DIR,
filename: isProdBuild ? '[name].bundle.[chunkhash].js' : '[name].js',
publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix
publicPath: '',
devtoolModuleFilenameTemplate: function (info) {
if (isProdBuild) {
return `webpack:///${info.resourcePath}`;
Expand Down Expand Up @@ -129,7 +128,7 @@ module.exports = (env, argv) => {
template: `${PUBLIC_DIR}/html-templates/${HTML_TEMPLATE}`,
filename: 'index.html',
templateParameters: {
PUBLIC_URL: PUBLIC_URL,
PUBLIC_URL: '',
},
}),
// Generate a service worker for fast local loads
Expand Down Expand Up @@ -179,7 +178,7 @@ module.exports = (env, argv) => {
//writeToDisk: true,
historyApiFallback: {
disableDotRule: true,
index: PUBLIC_URL + 'index.html',
index: 'index.html',
},
devMiddleware: {
writeToDisk: true,
Expand Down
14 changes: 9 additions & 5 deletions platform/app/.webpack/writePluginImportsFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ const pluginConfig = require('../pluginConfig.json');
const fs = require('fs');
const os = require('os');

const autogenerationDisclaimer = `
const autogenerationDisclaimer = `import { getPublicSubPath } from '@ohif/core';

// THIS FILE IS AUTOGENERATED AS PART OF THE EXTENSION AND MODE PLUGIN PROCESS.
// IT SHOULD NOT BE MODIFIED MANUALLY \n`;

const extractName = val => (typeof val === 'string' ? val : val.packageName);

const publicURL = process.env.PUBLIC_URL || '/';

function isAbsolutePath(path) {
return path.startsWith('http') || path.startsWith('/');
return path.startsWith('http');
}

function constructLines(input, categoryName) {
Expand Down Expand Up @@ -66,6 +65,11 @@ function getRuntimeLoadModesExtensions(modules) {
const dynamicLoad = [];
dynamicLoad.push(
'\n\n// Add a dynamic runtime loader',
'function getRuntimeImportPath(path) {',
" if (typeof path !== 'string' || path.startsWith('http')) return path;",
' return getPublicSubPath(path);',
'}',
'',
'async function loadModule(module) {',
" if (typeof module !== 'string') return module;"
);
Expand All @@ -77,7 +81,7 @@ function getRuntimeLoadModesExtensions(modules) {
if (module.importPath) {
dynamicLoad.push(
` if( module==="${packageName}") {`,
` const imported = await window.browserImportFunction('${isAbsolutePath(module.importPath) ? '' : publicURL}${module.importPath}');`,
` const imported = await window.browserImportFunction(getRuntimeImportPath('${module.importPath}'));`,
' return ' +
(module.globalName
? `window["${module.globalName}"];`
Expand Down
87 changes: 81 additions & 6 deletions platform/app/public/html-templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,87 @@
name="msapplication-TileColor"
content="#fff"
/>
<script type="text/javascript">
console.time('scriptToView');
(function () {
// Keep this inline runtime base-path bootstrap in sync with
// platform/core/src/utils/publicUrl.ts.
function normalizePublicUrl(value) {
var rawValue = typeof value === 'string' ? value.trim() : '';

if (!rawValue || rawValue === '.') {
return '/';
}

var normalized = rawValue.replace(/\\/g, '/');

if (!normalized.startsWith('/')) {
normalized = '/' + normalized;
}

normalized = normalized.replace(/\/{2,}/g, '/');

if (!normalized.endsWith('/')) {
normalized += '/';
}

return normalized;
}

function getLocationBasePathFromPathname(pathname) {
var locationPath = typeof pathname === 'string' && pathname.length > 0 ? pathname : '/';
var lowerPath = locationPath.toLowerCase();
var viewerIndex = lowerPath.lastIndexOf('/viewer');

if (viewerIndex >= 0) {
return normalizePublicUrl(locationPath.substring(0, viewerIndex));
}

if (lowerPath.endsWith('/index.html')) {
return normalizePublicUrl(
locationPath.substring(0, locationPath.length - '/index.html'.length)
);
}

if (locationPath === '/') {
return '/';
}

var lastSegment = locationPath.substring(locationPath.lastIndexOf('/') + 1);
if (lastSegment.indexOf('.') !== -1) {
return normalizePublicUrl(locationPath.substring(0, locationPath.lastIndexOf('/')));
}

return normalizePublicUrl(locationPath);
}

function resolveRuntimeBasePathFromWindow() {
var explicitBasePath =
window.__OHIF_BASE_PATH__ ||
window.PUBLIC_URL ||
(window.config && window.config.routerBasename);

if (typeof explicitBasePath === 'string' && explicitBasePath.trim().length > 0) {
return normalizePublicUrl(explicitBasePath);
}

return getLocationBasePathFromPathname(window.location.pathname || '/');
}

var basePath = resolveRuntimeBasePathFromWindow();

window.__OHIF_BASE_PATH__ = basePath;
window.PUBLIC_URL = basePath;

var baseElement = document.querySelector('base');
if (!baseElement) {
baseElement = document.createElement('base');
document.head.appendChild(baseElement);
}

baseElement.setAttribute('href', basePath);
})();
</script>
Comment thread
greptile-apps[bot] marked this conversation as resolved.
<meta
name="msapplication-TileImage"
content="<%= PUBLIC_URL %>assets/mstile-144x144.png"
Expand All @@ -42,10 +123,6 @@
name="msapplication-config"
content="<%= PUBLIC_URL %>assets/browserconfig.xml"
/>
<script type="text/javascript">
console.time('scriptToView');
window.PUBLIC_URL = '<%= PUBLIC_URL %>';
</script>
<link
rel="manifest"
href="<%= PUBLIC_URL %>manifest.json"
Expand Down Expand Up @@ -202,8 +279,6 @@
function browserImportFunction(moduleId) {
return import(moduleId);
}

window.PUBLIC_URL = '<%= PUBLIC_URL %>';
</script>

<!-- EXTENSIONS -->
Expand Down
84 changes: 80 additions & 4 deletions platform/app/public/html-templates/rollbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,86 @@
name="msapplication-TileColor"
content="#fff"
/>
<script type="text/javascript">
(function () {
// Keep this inline runtime base-path bootstrap in sync with
// platform/core/src/utils/publicUrl.ts.
function normalizePublicUrl(value) {
var rawValue = typeof value === 'string' ? value.trim() : '';

if (!rawValue || rawValue === '.') {
return '/';
}

var normalized = rawValue.replace(/\\/g, '/');

if (!normalized.startsWith('/')) {
normalized = '/' + normalized;
}

normalized = normalized.replace(/\/{2,}/g, '/');

if (!normalized.endsWith('/')) {
normalized += '/';
}

return normalized;
}

function getLocationBasePathFromPathname(pathname) {
var locationPath = typeof pathname === 'string' && pathname.length > 0 ? pathname : '/';
var lowerPath = locationPath.toLowerCase();
var viewerIndex = lowerPath.lastIndexOf('/viewer');

if (viewerIndex >= 0) {
return normalizePublicUrl(locationPath.substring(0, viewerIndex));
}

if (lowerPath.endsWith('/index.html')) {
return normalizePublicUrl(
locationPath.substring(0, locationPath.length - '/index.html'.length)
);
}

if (locationPath === '/') {
return '/';
}

var lastSegment = locationPath.substring(locationPath.lastIndexOf('/') + 1);
if (lastSegment.indexOf('.') !== -1) {
return normalizePublicUrl(locationPath.substring(0, locationPath.lastIndexOf('/')));
}

return normalizePublicUrl(locationPath);
}
Comment on lines +63 to +88

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

/viewer is matched as a substring, not a path segment.

lastIndexOf('/viewer') matches longer segments too (e.g. /viewers/123 or a deployment prefix like /viewer-prod/), causing the base path to be truncated incorrectly. For /viewer-prod/ this yields / instead of /viewer-prod/, breaking asset resolution for that deployment. Constrain the match to a full segment boundary. The same heuristic lives in platform/core/src/utils/publicUrl.ts; keep both in sync.

🐛 Proposed fix
           var viewerIndex = lowerPath.lastIndexOf('/viewer');

-          if (viewerIndex >= 0) {
+          var afterViewer = lowerPath.charAt(viewerIndex + '/viewer'.length);
+          if (viewerIndex >= 0 && (afterViewer === '' || afterViewer === '/')) {
             return normalizePublicUrl(locationPath.substring(0, viewerIndex));
           }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@platform/app/public/html-templates/rollbar.html` around lines 63 - 88, The
getLocationBasePathFromPathname function currently finds viewerIndex via
lastIndexOf('/viewer') which matches substrings inside segment names (e.g.
'/viewer-prod' or '/viewers/123'); change the detection to require a full path
segment boundary (match '/viewer' followed by '/' or end-of-string) when
computing viewerIndex, then use that bounded index to call normalizePublicUrl as
before; update the logic in getLocationBasePathFromPathname (and keep it in sync
with platform/core/src/utils/publicUrl.ts) so only the exact '/viewer' segment
is treated as the viewer route.


function resolveRuntimeBasePathFromWindow() {
var explicitBasePath =
window.__OHIF_BASE_PATH__ ||
window.PUBLIC_URL ||
(window.config && window.config.routerBasename);

if (typeof explicitBasePath === 'string' && explicitBasePath.trim().length > 0) {
return normalizePublicUrl(explicitBasePath);
}

return getLocationBasePathFromPathname(window.location.pathname || '/');
}

var basePath = resolveRuntimeBasePathFromWindow();

window.__OHIF_BASE_PATH__ = basePath;
window.PUBLIC_URL = basePath;

var baseElement = document.querySelector('base');
if (!baseElement) {
baseElement = document.createElement('base');
document.head.appendChild(baseElement);
}

baseElement.setAttribute('href', basePath);
})();
</script>
<meta
name="msapplication-TileImage"
content="<%= PUBLIC_URL %>assets/mstile-144x144.png"
Expand Down Expand Up @@ -178,10 +258,6 @@
rel="yandex-tableau-widget"
href="<%= PUBLIC_URL %>assets/yandex-browser-manifest.json"
/>

<script type="text/javascript">
window.PUBLIC_URL = '<%= PUBLIC_URL %>';
</script>
<script
type="text/javascript"
src="<%= PUBLIC_URL %>app-config.js"
Expand Down
18 changes: 9 additions & 9 deletions platform/app/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,47 @@
"orientation": "any",
"icons": [
{
"src": "/assets/android-chrome-36x36.png",
"src": "assets/android-chrome-36x36.png",
"sizes": "36x36",
"type": "image/png"
},
{
"src": "/assets/android-chrome-48x48.png",
"src": "assets/android-chrome-48x48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "/assets/android-chrome-72x72.png",
"src": "assets/android-chrome-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "/assets/android-chrome-96x96.png",
"src": "assets/android-chrome-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "/assets/android-chrome-144x144.png",
"src": "assets/android-chrome-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/assets/android-chrome-192x192.png",
"src": "assets/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/android-chrome-256x256.png",
"src": "assets/android-chrome-256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "/assets/android-chrome-384x384.png",
"src": "assets/android-chrome-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/assets/android-chrome-512x512.png",
"src": "assets/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
Expand Down
1 change: 1 addition & 0 deletions platform/app/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Entry point for development and production PWA builds.
*/
import 'regenerator-runtime/runtime';
import './setRuntimePublicPath';
import { createRoot } from 'react-dom/client';
import App from './App';
import React from 'react';
Expand Down
27 changes: 27 additions & 0 deletions platform/app/src/setRuntimePublicPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* global __webpack_public_path__ */

import {
normalizePublicUrl,
toRouterBasename,
resolveRuntimeBasePathFromWindow,
} from '@ohif/core';

const runtimePublicUrl = resolveRuntimeBasePathFromWindow();

window.__OHIF_BASE_PATH__ = runtimePublicUrl;
window.PUBLIC_URL = runtimePublicUrl;

if (window.config && !window.config.routerBasename) {
window.config.routerBasename = toRouterBasename(runtimePublicUrl);
}

__webpack_public_path__ = runtimePublicUrl;

export {
normalizePublicUrl,
toRouterBasename,
resolveRuntimeBasePathFromWindow as resolveRuntimeBasePath,
runtimePublicUrl,
};

export default runtimePublicUrl;
8 changes: 6 additions & 2 deletions platform/app/src/utils/publicUrl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
const publicUrl = (window as any).PUBLIC_URL || '/';
const routerBasename = (window as any).config?.routerBasename || publicUrl;
import { normalizePublicUrl, toRouterBasename } from '../../../core/src/utils/publicUrl';

const publicUrl = normalizePublicUrl(
(window as any).__OHIF_BASE_PATH__ || (window as any).PUBLIC_URL || '/'
);
const routerBasename = toRouterBasename((window as any).config?.routerBasename || publicUrl);

export { publicUrl, routerBasename };

Expand Down
Loading