From 3434e654cf420bbd1b482baf336f62508ddc8b4f Mon Sep 17 00:00:00 2001 From: Christoph Ladurner Date: Mon, 16 Dec 2024 13:26:12 +0100 Subject: [PATCH 1/4] fix: docs reference target not found --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 48a8c23..7909171 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -321,3 +321,5 @@ # Autodoc configuraton. autoclass_content = "both" + +nitpick_ignore = [("py:func", "flask_webpackext.project.flask_config")] From 4df8d8f1c53b43c28282da4c34ccf549456db5b3 Mon Sep 17 00:00:00 2001 From: Christoph Ladurner Date: Sun, 15 Sep 2024 00:01:49 +0200 Subject: [PATCH 2/4] context: make the bundle current_app unaware --- flask_webpackext/project.py | 125 ++++++++++++++++++++++-------------- tests/conftest.py | 3 +- 2 files changed, 78 insertions(+), 50 deletions(-) diff --git a/flask_webpackext/project.py b/flask_webpackext/project.py index 530c409..514591a 100644 --- a/flask_webpackext/project.py +++ b/flask_webpackext/project.py @@ -2,7 +2,7 @@ # # This file is part of Flask-WebpackExt # Copyright (C) 2017, 2018 CERN. -# Copyright (C) 2024 Graz University of Technology. +# Copyright (C) 2024-2025 Graz University of Technology. # # Flask-WebpackExt is free software; you can redistribute it and/or modify # it under the terms of the Revised BSD License; see LICENSE file for @@ -16,14 +16,48 @@ from flask.helpers import get_root_path from pywebpack import WebpackBundleProject as PyWebpackBundleProject from pywebpack import WebpackTemplateProject as PyWebpackTemplateProject +from pywebpack.helpers import cached +from werkzeug.utils import import_string -from .proxies import current_webpack +class _PathStorageMixin: + """Mixin class.""" + + @property + def path(self): + """Get path to project.""" + try: + return self.app.config["WEBPACKEXT_PROJECT_BUILDDIR"] + except KeyError: + return join(self.app.instance_path, "assets") + + @property + def dist_dir(self): + """Get dist dir.""" + try: + return self.app.config["WEBPACKEXT_PROJECT_DISTDIR"] + except KeyError: + return join(self.app.static_folder, "dist") -def flask_config(): - """Flask configuration injected in Webpack. + @property + def project(self): + project = self.app.config["WEBPACKEXT_PROJECT"] + if isinstance(project, str): + return import_string(project) + return project - :return: Dictionary which contains the information Flask-WebpackExt knows + @property + def storage_cls(self): + """Get storage class.""" + cls_ = self.app.config["WEBPACKEXT_STORAGE_CLS"] + if isinstance(cls_, str): + return import_string(cls_) + return cls_ + + def flask_config(self): + """Flask configuration injected in Webpack. + + :return: Dictionary which contains the information Flask-WebpackExt knows about a Webpack project and the absolute URLs for static files and assets. The dictionary consists of a key ``build`` with the following keys inside: @@ -34,54 +68,41 @@ def flask_config(): * ``assetsURL``: URL to access the built files. * ``staticPath``: Absolute path to the generated static directory. * ``staticURL``: URL to access the static files.. - """ - assets_url = current_app.config["WEBPACKEXT_PROJECT_DISTURL"] - if not assets_url.endswith("/"): - assets_url += "/" - static_url = current_app.static_url_path - if not static_url.endswith("/"): - static_url += "/" - - return { - "build": { - "debug": current_app.debug, - "context": current_webpack.project.path, - "assetsPath": current_app.config["WEBPACKEXT_PROJECT_DISTDIR"], - "assetsURL": assets_url, - "staticPath": current_app.static_folder, - "staticURL": static_url, + """ + assets_url = self.app.config["WEBPACKEXT_PROJECT_DISTURL"] + if not assets_url.endswith("/"): + assets_url += "/" + static_url = self.app.static_url_path + if not static_url.endswith("/"): + static_url += "/" + + return { + "build": { + "debug": self.app.debug, + "context": self.project.path, + "assetsPath": self.app.config["WEBPACKEXT_PROJECT_DISTDIR"], + "assetsURL": assets_url, + "staticPath": self.app.static_folder, + "staticURL": static_url, + } } - } - -def flask_allowed_copy_paths(): - """Get the allowed copy paths from the Flask application.""" - return [ - current_app.instance_path, - current_webpack.project.path, - current_app.static_folder, - current_app.config["WEBPACKEXT_PROJECT_DISTDIR"], - ] - - -class _PathStorageMixin(object): - """Mixin class.""" - - @property - def path(self): - """Get path to project.""" - return current_app.config["WEBPACKEXT_PROJECT_BUILDDIR"] - - @property - def storage_cls(self): - """Get storage class.""" - return current_webpack.storage_cls + def flask_allowed_copy_paths(self): + """Get the allowed copy paths from the Flask application.""" + return [ + self.app.instance_path, + self.path, + self.app.static_folder, + self.dist_dir, + ] class WebpackTemplateProject(_PathStorageMixin, PyWebpackTemplateProject): """Flask webpack template project.""" - def __init__(self, import_name, project_folder=None, config=None, config_path=None): + def __init__( + self, import_name, project_folder=None, config=None, config_path=None, app=None + ): """Initialize project. :param import_name: Name of the module where the @@ -96,11 +117,13 @@ def __init__(self, import_name, project_folder=None, config=None, config_path=No ``config.json``, this file is generated by :func:`flask_webpackext.project.flask_config`. """ + self.app = app or current_app project_template_dir = join(get_root_path(import_name), project_folder) + super().__init__( None, project_template_dir=project_template_dir, - config=config or flask_config, + config=config or self.flask_config, config_path=config_path, ) @@ -116,6 +139,7 @@ def __init__( config=None, config_path=None, allowed_copy_paths=None, + app=None, ): """Initialize templated folder. @@ -141,12 +165,15 @@ class is instantiated. It is used to determine the absolute path :param allowed_copy_paths: List of paths (absolute, or relative to the `config_path`) that are allowed for bundle copy instructions. """ + self.app = app or current_app project_template_dir = join(get_root_path(import_name), project_folder) + config = config or self.flask_config + allowed_copy_paths = allowed_copy_paths or self.flask_allowed_copy_paths super().__init__( None, project_template_dir=project_template_dir, bundles=bundles, - config=config or flask_config, + config=config, config_path=config_path, - allowed_copy_paths=allowed_copy_paths or flask_allowed_copy_paths, + allowed_copy_paths=allowed_copy_paths, ) diff --git a/tests/conftest.py b/tests/conftest.py index e63e1cc..8927b61 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ # # This file is part of Flask-WebpackExt # Copyright (C) 2017 CERN. +# Copyright (C) 2024 Graz University of Technology. # # Flask-WebpackExt is free software; you can redistribute it and/or modify # it under the terms of the Revised BSD License; see LICENSE file for @@ -128,7 +129,7 @@ def bundles(): @pytest.fixture() def projectbundle(app, bundles): """Webpack bundle project.""" - project = WebpackBundleProject(__name__, "assetsbundle", bundles=bundles) + project = WebpackBundleProject(__name__, "assetsbundle", bundles=bundles, app=app) app.config.update( { "WEBPACKEXT_PROJECT": project, From da488a08ecd69f51dc77454c6289ecf43cf1c915 Mon Sep 17 00:00:00 2001 From: Christoph Ladurner Date: Thu, 2 Jan 2025 14:04:36 +0100 Subject: [PATCH 3/4] project: add configuration for js package manager * it is possible to choose between npm and pnpm over the configuration variable JAVASCRIPT_PACKAGES_MANAGER. to be backward compatible npm is the default package manager. --- flask_webpackext/project.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flask_webpackext/project.py b/flask_webpackext/project.py index 514591a..2c1132e 100644 --- a/flask_webpackext/project.py +++ b/flask_webpackext/project.py @@ -14,6 +14,7 @@ from flask import current_app from flask.helpers import get_root_path +from pynpm import NPMPackage, PNPMPackage from pywebpack import WebpackBundleProject as PyWebpackBundleProject from pywebpack import WebpackTemplateProject as PyWebpackTemplateProject from pywebpack.helpers import cached @@ -46,6 +47,15 @@ def project(self): return import_string(project) return project + @property + def npmpkg(self): + """Get API to NPM package.""" + js_packages_manager = self.app.config.get("JAVASCRIPT_PACKAGES_MANAGER", "npm") + if js_packages_manager == "pnpm": + return PNPMPackage(self.path) + + return NPMPackage(self.path) + @property def storage_cls(self): """Get storage class.""" From af8dbb80e80780f4c19aaaf1b06701ad521894fc Mon Sep 17 00:00:00 2001 From: Christoph Ladurner Date: Tue, 14 Jan 2025 21:40:42 +0100 Subject: [PATCH 4/4] project: sneak in app * this makes it possible to reduce usage of current_app and enables performance boosts on invenio-cli --- flask_webpackext/project.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flask_webpackext/project.py b/flask_webpackext/project.py index 2c1132e..ae57f69 100644 --- a/flask_webpackext/project.py +++ b/flask_webpackext/project.py @@ -187,3 +187,13 @@ class is instantiated. It is used to determine the absolute path config_path=config_path, allowed_copy_paths=allowed_copy_paths, ) + + @property + @cached + def entry(self): + """Get webpack entry points.""" + # this enables to use the bundle without the current_app context + for bundle in self.bundles: + bundle.app = self.app + + return super().entry