diff --git a/vizro-core/changelog.d/20240311_161236_antony.milne_external_assets.md b/vizro-core/changelog.d/20240311_161236_antony.milne_external_assets.md new file mode 100644 index 000000000..d5d10a7f1 --- /dev/null +++ b/vizro-core/changelog.d/20240311_161236_antony.milne_external_assets.md @@ -0,0 +1,47 @@ + + + + + + + + +### Fixed + +- Fix path to built-in Vizro assets when `requests_pathname_prefix` is not the same as `routes_pathname_prefix` ([#358](https://github.com/mckinsey/vizro/pull/358)) + diff --git a/vizro-core/docs/pages/user-guides/run.md b/vizro-core/docs/pages/user-guides/run.md index fbaa1be1e..5479d58be 100644 --- a/vizro-core/docs/pages/user-guides/run.md +++ b/vizro-core/docs/pages/user-guides/run.md @@ -124,4 +124,4 @@ A Vizro app wraps a Dash app, which itself wraps a Flask app. Hence to deploy a In particular, `app = Vizro()` exposes the Flask app through `app.dash.server`. As in the [above example with Gunicorn](#gunicorn), this provides the application instance to a WSGI server. -[`Vizro`][vizro.Vizro] accepts `**kwargs` that are passed through to `Dash`. This allows you to configure the underlying Dash app using the same [argumentst that are available](https://dash.plotly.com/reference#dash.dash) in `Dash`. For example, in a deployment context, you might like to specify a custom `url_base_pathname` to serve your Vizro app at a specific URL rather than at your domain root. +[`Vizro`][vizro.Vizro] accepts `**kwargs` that are passed through to `Dash`. This allows you to configure the underlying Dash app using the same [arguments that are available](https://dash.plotly.com/reference#dash.dash) in `Dash`. For example, in a deployment context, you might like to specify a custom `url_base_pathname` to serve your Vizro app at a specific URL rather than at your domain root. diff --git a/vizro-core/src/vizro/_vizro.py b/vizro-core/src/vizro/_vizro.py index d7a221fd1..d9703c247 100644 --- a/vizro-core/src/vizro/_vizro.py +++ b/vizro-core/src/vizro/_vizro.py @@ -37,11 +37,11 @@ def __init__(self, **kwargs): # Include Vizro assets (in the static folder) as external scripts and stylesheets. We extend self.dash.config # objects so the user can specify additional external_scripts and external_stylesheets via kwargs. vizro_assets_folder = Path(__file__).with_name("static") - static_url_path = self.dash.config.requests_pathname_prefix + STATIC_URL_PREFIX - vizro_css = self._get_external_assets(static_url_path, vizro_assets_folder, "css") + requests_pathname_prefix = self.dash.config.requests_pathname_prefix + vizro_css = [requests_pathname_prefix + path for path in self._get_external_assets(vizro_assets_folder, "css")] vizro_js = [ - {"src": path, "type": "module"} - for path in self._get_external_assets(static_url_path, vizro_assets_folder, "js") + {"src": requests_pathname_prefix + path, "type": "module"} + for path in self._get_external_assets(vizro_assets_folder, "js") ] self.dash.config.external_stylesheets.extend(vizro_css) self.dash.config.external_scripts.extend(vizro_js) @@ -49,13 +49,14 @@ def __init__(self, **kwargs): # Serve all assets (including files other than css and js) that live in vizro_assets_folder at the # route /vizro. Based on code in Dash.init_app that serves assets_folder. This respects the case that the # dashboard is not hosted at the root of the server, e.g. http://www.example.com/dashboard/vizro. - blueprint_prefix = self.dash.config.routes_pathname_prefix.replace("/", "_").replace(".", "_") + routes_pathname_prefix = self.dash.config.routes_pathname_prefix + blueprint_prefix = routes_pathname_prefix.replace("/", "_").replace(".", "_") self.dash.server.register_blueprint( flask.Blueprint( f"{blueprint_prefix}vizro_assets", self.dash.config.name, static_folder=vizro_assets_folder, - static_url_path=static_url_path, + static_url_path=routes_pathname_prefix + STATIC_URL_PREFIX, ) ) @@ -119,10 +120,12 @@ def _reset(): dash._pages.CONFIG.__dict__.clear() @staticmethod - def _get_external_assets(new_path: str, folder: Path, extension: str) -> List[str]: - """Returns a list of paths to assets with given `extension` in `folder`, prefixed with `new_path`. + def _get_external_assets(folder: Path, extension: str) -> List[str]: + """Returns a list of paths to assets with given `extension` in `folder`, prefixed with `STATIC_URL_PREFIX`. - e.g. with new_path="/vizro", extension="css", folder="/path/to/vizro/vizro-core/src/vizro/static", - we will get ["/vizro/css/accordion.css", "/vizro/css/button.css", ...]. + e.g. with STATIC_URL_PREFIX="vizro", extension="css", folder="/path/to/vizro/vizro-core/src/vizro/static", + we will get ["vizro/css/accordion.css", "vizro/css/button.css", ...]. """ - return sorted((new_path / path.relative_to(folder)).as_posix() for path in folder.rglob(f"*.{extension}")) + return sorted( + (STATIC_URL_PREFIX / path.relative_to(folder)).as_posix() for path in folder.rglob(f"*.{extension}") + )