Skip to content
Closed
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
2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,5 @@

# Autodoc configuraton.
autoclass_content = "both"

nitpick_ignore = [("py:func", "flask_webpackext.project.flask_config")]
145 changes: 96 additions & 49 deletions flask_webpackext/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -14,16 +14,60 @@

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
from werkzeug.utils import import_string

from .proxies import current_webpack

class _PathStorageMixin:
"""Mixin class."""

def flask_config():
"""Flask configuration injected in Webpack.
@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")

:return: Dictionary which contains the information Flask-WebpackExt knows
@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")

@property
def project(self):
project = self.app.config["WEBPACKEXT_PROJECT"]
if isinstance(project, str):
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."""
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:
Expand All @@ -34,54 +78,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
Expand All @@ -96,11 +127,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,
)

Expand All @@ -116,6 +149,7 @@ def __init__(
config=None,
config_path=None,
allowed_copy_paths=None,
app=None,
):
"""Initialize templated folder.

Expand All @@ -141,12 +175,25 @@ 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,
)

@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
3 changes: 2 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down