mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 16:51:09 -05:00
okay fine
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
__author__ = "Vinta Software"
|
||||
__version__ = "3.1.1"
|
||||
|
||||
import django
|
||||
|
||||
if django.VERSION < (3, 2): # pragma: no cover
|
||||
default_app_config = "webpack_loader.apps.WebpackLoaderConfig"
|
||||
29
.venv/lib/python3.12/site-packages/webpack_loader/apps.py
Normal file
29
.venv/lib/python3.12/site-packages/webpack_loader/apps.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from .errors import BAD_CONFIG_ERROR
|
||||
|
||||
|
||||
def webpack_cfg_check(*args, **kwargs):
|
||||
'''Test if config is compatible or not'''
|
||||
from django.conf import settings
|
||||
|
||||
check_failed = False
|
||||
user_config = getattr(settings, 'WEBPACK_LOADER', {})
|
||||
try:
|
||||
user_config = [dict({}, **cfg) for cfg in user_config.values()]
|
||||
except TypeError:
|
||||
check_failed = True
|
||||
|
||||
errors = []
|
||||
if check_failed:
|
||||
errors.append(BAD_CONFIG_ERROR)
|
||||
return errors
|
||||
|
||||
|
||||
class WebpackLoaderConfig(AppConfig):
|
||||
name = 'webpack_loader'
|
||||
verbose_name = "Webpack Loader"
|
||||
|
||||
def ready(self):
|
||||
from django.core.checks import register, Tags
|
||||
register(Tags.compatibility)(webpack_cfg_check)
|
||||
37
.venv/lib/python3.12/site-packages/webpack_loader/config.py
Normal file
37
.venv/lib/python3.12/site-packages/webpack_loader/config.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
__all__ = ('load_config',)
|
||||
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
'DEFAULT': {
|
||||
'CACHE': not settings.DEBUG,
|
||||
'BUNDLE_DIR_NAME': 'webpack_bundles/',
|
||||
'STATS_FILE': 'webpack-stats.json',
|
||||
# FIXME: Explore usage of fsnotify
|
||||
'POLL_INTERVAL': 0.1,
|
||||
'TIMEOUT': None,
|
||||
'IGNORE': [r'.+\.hot-update.js', r'.+\.map'],
|
||||
'LOADER_CLASS': 'webpack_loader.loaders.WebpackLoader',
|
||||
'INTEGRITY': False,
|
||||
# Whenever the global setting for SKIP_COMMON_CHUNKS is changed, please
|
||||
# update the fallback value in get_skip_common_chunks (utils.py).
|
||||
'SKIP_COMMON_CHUNKS': False,
|
||||
}
|
||||
}
|
||||
|
||||
user_config = getattr(settings, 'WEBPACK_LOADER', DEFAULT_CONFIG)
|
||||
|
||||
user_config = dict(
|
||||
(name, dict(DEFAULT_CONFIG['DEFAULT'], **cfg))
|
||||
for name, cfg in user_config.items()
|
||||
)
|
||||
|
||||
for entry in user_config.values():
|
||||
entry['ignores'] = [re.compile(I) for I in entry['IGNORE']]
|
||||
|
||||
|
||||
def load_config(name):
|
||||
return user_config[name]
|
||||
@@ -0,0 +1,22 @@
|
||||
from jinja2.ext import Extension
|
||||
from jinja2.runtime import Context
|
||||
from jinja2.utils import pass_context
|
||||
|
||||
from ..templatetags.webpack_loader import get_files, render_bundle
|
||||
|
||||
|
||||
@pass_context
|
||||
def _render_bundle(context: Context, *args, **kwargs):
|
||||
return render_bundle(context, *args, **kwargs)
|
||||
|
||||
|
||||
@pass_context
|
||||
def _get_files(context: Context, *args, **kwargs):
|
||||
return get_files(context, *args, **kwargs)
|
||||
|
||||
|
||||
class WebpackExtension(Extension):
|
||||
def __init__(self, environment):
|
||||
super(WebpackExtension, self).__init__(environment)
|
||||
environment.globals["render_bundle"] = _render_bundle
|
||||
environment.globals["webpack_get_files"] = _get_files
|
||||
@@ -0,0 +1,9 @@
|
||||
from django.core.checks import Error
|
||||
|
||||
|
||||
BAD_CONFIG_ERROR = Error(
|
||||
'Error while parsing WEBPACK_LOADER configuration',
|
||||
hint='Is WEBPACK_LOADER config valid?',
|
||||
obj='django.conf.settings.WEBPACK_LOADER',
|
||||
id='django-webpack-loader.E001',
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
__all__ = (
|
||||
'WebpackError',
|
||||
'WebpackLoaderBadStatsError',
|
||||
'WebpackLoaderTimeoutError',
|
||||
'WebpackBundleLookupError'
|
||||
)
|
||||
|
||||
|
||||
class BaseWebpackLoaderException(Exception):
|
||||
"""
|
||||
Base exception for django-webpack-loader.
|
||||
"""
|
||||
|
||||
|
||||
class WebpackError(BaseWebpackLoaderException):
|
||||
"""
|
||||
General webpack loader error.
|
||||
"""
|
||||
|
||||
|
||||
class WebpackLoaderBadStatsError(BaseWebpackLoaderException):
|
||||
"""
|
||||
The stats file does not contain valid data.
|
||||
"""
|
||||
|
||||
|
||||
class WebpackLoaderTimeoutError(BaseWebpackLoaderException):
|
||||
"""
|
||||
The bundle took too long to compile.
|
||||
"""
|
||||
|
||||
|
||||
class WebpackBundleLookupError(BaseWebpackLoaderException):
|
||||
"""
|
||||
The bundle name was invalid.
|
||||
"""
|
||||
@@ -0,0 +1,9 @@
|
||||
import warnings
|
||||
|
||||
from .loaders import * # noqa
|
||||
|
||||
warnings.warn(
|
||||
"The 'webpack_loader.loader' module has been renamed to 'webpack_loader.loaders'. "
|
||||
"Please update your imports and config to use the new module.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
173
.venv/lib/python3.12/site-packages/webpack_loader/loaders.py
Normal file
173
.venv/lib/python3.12/site-packages/webpack_loader/loaders.py
Normal file
@@ -0,0 +1,173 @@
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
from io import open
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
|
||||
from .exceptions import (
|
||||
WebpackError,
|
||||
WebpackLoaderBadStatsError,
|
||||
WebpackLoaderTimeoutError,
|
||||
WebpackBundleLookupError,
|
||||
)
|
||||
|
||||
|
||||
class WebpackLoader:
|
||||
_assets = {}
|
||||
|
||||
def __init__(self, name, config):
|
||||
self.name = name
|
||||
self.config = config
|
||||
|
||||
def load_assets(self):
|
||||
try:
|
||||
with open(self.config["STATS_FILE"], encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except IOError:
|
||||
raise IOError(
|
||||
"Error reading {0}. Are you sure webpack has generated "
|
||||
"the file and the path is correct?".format(self.config["STATS_FILE"])
|
||||
)
|
||||
|
||||
def get_assets(self):
|
||||
if self.config["CACHE"]:
|
||||
if self.name not in self._assets:
|
||||
self._assets[self.name] = self.load_assets()
|
||||
return self._assets[self.name]
|
||||
return self.load_assets()
|
||||
|
||||
def get_asset_by_source_filename(self, name):
|
||||
files = self.get_assets()["assets"].values()
|
||||
return next((x for x in files if x.get("sourceFilename") == name), None)
|
||||
|
||||
def get_integrity_attr(self, chunk):
|
||||
if not self.config.get("INTEGRITY"):
|
||||
return " "
|
||||
|
||||
integrity = chunk.get("integrity")
|
||||
if not integrity:
|
||||
raise WebpackLoaderBadStatsError(
|
||||
"The stats file does not contain valid data: INTEGRITY is set to True, "
|
||||
'but chunk does not contain "integrity" key. Maybe you forgot to add '
|
||||
"integrity: true in your BundleTracker configuration?"
|
||||
)
|
||||
|
||||
return ' integrity="{}" '.format(integrity.partition(" ")[0])
|
||||
|
||||
def filter_chunks(self, chunks):
|
||||
filtered_chunks = []
|
||||
|
||||
for chunk in chunks:
|
||||
ignore = any(regex.match(chunk) for regex in self.config["ignores"])
|
||||
if not ignore:
|
||||
filtered_chunks.append(chunk)
|
||||
|
||||
return filtered_chunks
|
||||
|
||||
def map_chunk_files_to_url(self, chunks):
|
||||
assets = self.get_assets()
|
||||
files = assets["assets"]
|
||||
|
||||
add_integrity = self.config.get("INTEGRITY")
|
||||
|
||||
for chunk in chunks:
|
||||
url = self.get_chunk_url(files[chunk])
|
||||
|
||||
if add_integrity:
|
||||
yield {
|
||||
"name": chunk,
|
||||
"url": url,
|
||||
"integrity": files[chunk].get("integrity"),
|
||||
}
|
||||
else:
|
||||
yield {"name": chunk, "url": url}
|
||||
|
||||
def get_chunk_url(self, chunk_file):
|
||||
public_path = chunk_file.get("publicPath")
|
||||
if public_path and public_path != "auto":
|
||||
return public_path
|
||||
|
||||
# Use os.path.normpath for Windows paths
|
||||
relpath = os.path.normpath(
|
||||
os.path.join(self.config["BUNDLE_DIR_NAME"], chunk_file["name"])
|
||||
)
|
||||
return staticfiles_storage.url(relpath)
|
||||
|
||||
def get_bundle(self, bundle_name):
|
||||
assets = self.get_assets()
|
||||
|
||||
# poll when debugging and block request until bundle is compiled
|
||||
# or the build times out
|
||||
if settings.DEBUG:
|
||||
timeout = self.config["TIMEOUT"] or 0
|
||||
timed_out = False
|
||||
start = time.time()
|
||||
while assets["status"] == "compile" and not timed_out:
|
||||
time.sleep(self.config["POLL_INTERVAL"])
|
||||
if timeout and (time.time() - timeout > start):
|
||||
timed_out = True
|
||||
assets = self.get_assets()
|
||||
|
||||
if timed_out:
|
||||
raise WebpackLoaderTimeoutError(
|
||||
"Timed Out. Bundle `{0}` took more than {1} seconds "
|
||||
"to compile.".format(bundle_name, timeout)
|
||||
)
|
||||
|
||||
if assets.get("status") == "done":
|
||||
chunks = assets["chunks"].get(bundle_name, None)
|
||||
if chunks is None:
|
||||
raise WebpackBundleLookupError(
|
||||
"Cannot resolve bundle {0}.".format(bundle_name)
|
||||
)
|
||||
|
||||
filtered_chunks = self.filter_chunks(chunks)
|
||||
|
||||
for chunk in filtered_chunks:
|
||||
asset = assets["assets"][chunk]
|
||||
if asset is None:
|
||||
raise WebpackBundleLookupError(
|
||||
"Cannot resolve asset {0}.".format(chunk)
|
||||
)
|
||||
|
||||
return self.map_chunk_files_to_url(filtered_chunks)
|
||||
|
||||
elif assets.get("status") == "error":
|
||||
if "file" not in assets:
|
||||
assets["file"] = ""
|
||||
if "error" not in assets:
|
||||
assets["error"] = "Unknown Error"
|
||||
if "message" not in assets:
|
||||
assets["message"] = ""
|
||||
error = """
|
||||
{error} in {file}
|
||||
{message}
|
||||
""".format(**assets)
|
||||
raise WebpackError(error)
|
||||
|
||||
raise WebpackLoaderBadStatsError(
|
||||
"The stats file does not contain valid data. Make sure "
|
||||
"webpack-bundle-tracker plugin is enabled and try to run "
|
||||
"webpack again."
|
||||
)
|
||||
|
||||
|
||||
class FakeWebpackLoader(WebpackLoader):
|
||||
"""
|
||||
A fake loader to help run Django tests.
|
||||
|
||||
For running tests where `render_bundle` is used but assets aren't built.
|
||||
"""
|
||||
|
||||
def get_assets(self):
|
||||
return {}
|
||||
|
||||
def get_bundle(self, _bundle_name):
|
||||
return [
|
||||
{
|
||||
"name": "test.bundle.js",
|
||||
"url": "http://localhost/static/webpack_bundles/test.bundle.js",
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
# will hook into collectstatic
|
||||
@@ -0,0 +1,84 @@
|
||||
from warnings import warn
|
||||
|
||||
from django.template import Library
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from .. import utils
|
||||
|
||||
register = Library()
|
||||
_WARNING_MESSAGE = (
|
||||
'You have specified skip_common_chunks=True but the passed context '
|
||||
'doesn\'t have a request. django_webpack_loader needs a request object to '
|
||||
'filter out duplicate chunks. Please see https://github.com/django-webpack'
|
||||
'/django-webpack-loader#use-skip_common_chunks-on-render_bundle')
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def render_bundle(
|
||||
context, bundle_name, extension=None, config='DEFAULT', suffix='',
|
||||
attrs='', is_preload=False, skip_common_chunks=None):
|
||||
if skip_common_chunks is None:
|
||||
skip_common_chunks = utils.get_skip_common_chunks(config)
|
||||
|
||||
url_to_tag_dict = utils.get_as_url_to_tag_dict(
|
||||
bundle_name, extension=extension, config=config, suffix=suffix,
|
||||
attrs=attrs, is_preload=is_preload)
|
||||
|
||||
request = context.get('request')
|
||||
if request is None:
|
||||
if skip_common_chunks:
|
||||
warn(message=_WARNING_MESSAGE, category=RuntimeWarning)
|
||||
return mark_safe('\n'.join(url_to_tag_dict.values()))
|
||||
|
||||
used_urls = getattr(request, '_webpack_loader_used_urls', None)
|
||||
if not used_urls:
|
||||
used_urls = request._webpack_loader_used_urls = set()
|
||||
if skip_common_chunks:
|
||||
url_to_tag_dict = {url: tag for url, tag in url_to_tag_dict.items() if url not in used_urls}
|
||||
used_urls.update(url_to_tag_dict.keys())
|
||||
return mark_safe('\n'.join(url_to_tag_dict.values()))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def webpack_static(asset_name, config='DEFAULT'):
|
||||
return utils.get_static(asset_name, config=config)
|
||||
|
||||
@register.simple_tag
|
||||
def webpack_asset(asset_name, config='DEFAULT'):
|
||||
return utils.get_asset(asset_name, config=config)
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def get_files(
|
||||
context, bundle_name, extension=None, config='DEFAULT',
|
||||
skip_common_chunks=None):
|
||||
"""
|
||||
Returns all chunks in the given bundle.
|
||||
Example usage::
|
||||
|
||||
{% get_files 'editor' 'css' as editor_css_chunks %}
|
||||
CKEDITOR.config.contentsCss = '{{ editor_css_chunks.0.url }}';
|
||||
|
||||
:param context: The request, if you want to use `skip_common_chunks`
|
||||
:param bundle_name: The name of the bundle
|
||||
:param extension: (optional) filter by extension
|
||||
:param config: (optional) the name of the configuration
|
||||
:param skip_common_chunks: (optional) `True` if you want to skip returning already rendered common chunks
|
||||
:return: a list of matching chunks
|
||||
"""
|
||||
if skip_common_chunks is None:
|
||||
skip_common_chunks = utils.get_skip_common_chunks(config)
|
||||
|
||||
result = utils.get_files(bundle_name, extension=extension, config=config)
|
||||
|
||||
request = context.get('request')
|
||||
if request is None:
|
||||
if skip_common_chunks:
|
||||
warn(message=_WARNING_MESSAGE, category=RuntimeWarning)
|
||||
return result
|
||||
|
||||
used_urls = getattr(request, '_webpack_loader_used_urls', None)
|
||||
if not used_urls:
|
||||
used_urls = set()
|
||||
if skip_common_chunks:
|
||||
result = [chunk for chunk in result if chunk['url'] not in used_urls]
|
||||
return result
|
||||
141
.venv/lib/python3.12/site-packages/webpack_loader/utils.py
Normal file
141
.venv/lib/python3.12/site-packages/webpack_loader/utils.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from collections import OrderedDict
|
||||
from importlib import import_module
|
||||
from django.conf import settings
|
||||
from .config import load_config
|
||||
|
||||
_loaders = {}
|
||||
|
||||
|
||||
def import_string(dotted_path):
|
||||
'''
|
||||
This is a rough copy of django's import_string, which wasn't introduced until Django 1.7
|
||||
|
||||
Once this package's support for Django 1.6 has been removed, this can be safely replaced with
|
||||
`from django.utils.module_loading import import_string`
|
||||
'''
|
||||
try:
|
||||
module_path, class_name = dotted_path.rsplit('.', 1)
|
||||
module = import_module(module_path)
|
||||
return getattr(module, class_name)
|
||||
except (ValueError, AttributeError, ImportError):
|
||||
raise ImportError('%s doesn\'t look like a valid module path' % dotted_path)
|
||||
|
||||
|
||||
def get_loader(config_name):
|
||||
if config_name not in _loaders:
|
||||
config = load_config(config_name)
|
||||
loader_class = import_string(config['LOADER_CLASS'])
|
||||
_loaders[config_name] = loader_class(config_name, config)
|
||||
return _loaders[config_name]
|
||||
|
||||
|
||||
def get_skip_common_chunks(config_name):
|
||||
loader = get_loader(config_name)
|
||||
# The global default is currently False, whenever that is changed, change
|
||||
# this fallback value as well which is present to provide backwards
|
||||
# compatibility.
|
||||
return loader.config.get('SKIP_COMMON_CHUNKS', False)
|
||||
|
||||
|
||||
def _filter_by_extension(bundle, extension):
|
||||
'''Return only files with the given extension'''
|
||||
for chunk in bundle:
|
||||
if chunk['name'].endswith('.{0}'.format(extension)):
|
||||
yield chunk
|
||||
|
||||
|
||||
def _get_bundle(loader, bundle_name, extension):
|
||||
bundle = loader.get_bundle(bundle_name)
|
||||
if extension:
|
||||
bundle = _filter_by_extension(bundle, extension)
|
||||
return bundle
|
||||
|
||||
|
||||
def get_files(bundle_name, extension=None, config='DEFAULT'):
|
||||
'''Returns list of chunks from named bundle'''
|
||||
loader = get_loader(config)
|
||||
return list(_get_bundle(loader, bundle_name, extension))
|
||||
|
||||
|
||||
def get_as_url_to_tag_dict(bundle_name, extension=None, config='DEFAULT', suffix='', attrs='', is_preload=False):
|
||||
'''
|
||||
Get a dict of URLs to formatted <script> & <link> tags for the assets in the
|
||||
named bundle.
|
||||
|
||||
:param bundle_name: The name of the bundle
|
||||
:param extension: (optional) filter by extension, eg. 'js' or 'css'
|
||||
:param config: (optional) the name of the configuration
|
||||
:return: a dict of URLs to formatted tags as strings
|
||||
'''
|
||||
|
||||
loader = get_loader(config)
|
||||
bundle = _get_bundle(loader, bundle_name, extension)
|
||||
result = OrderedDict()
|
||||
|
||||
for chunk in bundle:
|
||||
if chunk['name'].endswith(('.js', '.js.gz')):
|
||||
if is_preload:
|
||||
result[chunk['url']] = (
|
||||
'<link rel="preload" as="script" href="{0}" {1}/>'
|
||||
).format(''.join([chunk['url'], suffix]), attrs)
|
||||
else:
|
||||
result[chunk['url']] = (
|
||||
'<script src="{0}"{2}{1}></script>'
|
||||
).format(
|
||||
''.join([chunk['url'], suffix]),
|
||||
attrs,
|
||||
loader.get_integrity_attr(chunk),
|
||||
)
|
||||
elif chunk['name'].endswith(('.css', '.css.gz')):
|
||||
result[chunk['url']] = (
|
||||
'<link href="{0}" rel={2}{3}{1}/>'
|
||||
).format(
|
||||
''.join([chunk['url'], suffix]),
|
||||
attrs,
|
||||
'"stylesheet"' if not is_preload else '"preload" as="style"',
|
||||
loader.get_integrity_attr(chunk),
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def get_as_tags(bundle_name, extension=None, config='DEFAULT', suffix='', attrs='', is_preload=False):
|
||||
'''
|
||||
Get a list of formatted <script> & <link> tags for the assets in the
|
||||
named bundle.
|
||||
|
||||
:param bundle_name: The name of the bundle
|
||||
:param extension: (optional) filter by extension, eg. 'js' or 'css'
|
||||
:param config: (optional) the name of the configuration
|
||||
:return: a list of formatted tags as strings
|
||||
'''
|
||||
return list(get_as_url_to_tag_dict(bundle_name, extension, config, suffix, attrs, is_preload).values())
|
||||
|
||||
|
||||
def get_static(asset_name, config='DEFAULT'):
|
||||
'''
|
||||
Equivalent to Django's 'static' look up but for webpack assets.
|
||||
|
||||
:param asset_name: the name of the asset
|
||||
:param config: (optional) the name of the configuration
|
||||
:return: path to webpack asset as a string
|
||||
'''
|
||||
public_path = get_loader(config).get_assets().get('publicPath')
|
||||
if not public_path or public_path == 'auto':
|
||||
public_path = getattr(settings, 'STATIC_URL')
|
||||
|
||||
return '{0}{1}'.format(public_path, asset_name)
|
||||
|
||||
def get_asset(source_filename, config='DEFAULT'):
|
||||
'''
|
||||
Equivalent to Django's 'static' look up but for webpack assets, given its original filename.
|
||||
Allow handling files whose path has been modified by Webpack processing, such as including content hash to filename.
|
||||
|
||||
:param source_filename: the source filename of the asset
|
||||
:param config: (optional) the name of the configuration
|
||||
:return: path to webpack asset as a string
|
||||
'''
|
||||
loader = get_loader(config)
|
||||
asset = loader.get_asset_by_source_filename(source_filename)
|
||||
if not asset: return None
|
||||
|
||||
return get_static(asset['name'], config)
|
||||
Reference in New Issue
Block a user