From 89b7cf0e8d72d83b15b419d774a114f8e7379149 Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Wed, 19 Jan 2022 00:23:09 +0100 Subject: [PATCH] [enh] bundle js_dependencies of plugins --- .gitignore | 1 + searx/resource_bundler.py | 63 ++++++++++++++++++++++++++++++++ searx/templates/oscar/base.html | 6 +-- searx/templates/simple/base.html | 6 +-- searx/webapp.py | 9 ++--- 5 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 searx/resource_bundler.py diff --git a/.gitignore b/.gitignore index efea6c872..714f74581 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,6 @@ cache/ build/ dist/ local/ +searx/static/bundles/ gh-pages/ *.egg-info/ diff --git a/searx/resource_bundler.py b/searx/resource_bundler.py new file mode 100644 index 000000000..2b747bd05 --- /dev/null +++ b/searx/resource_bundler.py @@ -0,0 +1,63 @@ +""" +Bundles ``js_dependencies`` of plugins to remove the overhead of separate HTTP requests. +""" +import os +import os.path +import itertools +import pathlib +from typing import Iterable, Dict + +from flask import url_for + +from . import settings +from .webutils import get_themes +from .plugins import plugins, Plugin + +templates_path = settings['ui']['templates_path'] +themes = get_themes(templates_path) + + +def build_bundles(): + static_path = settings['ui']['static_path'] + bundles_path = pathlib.Path(static_path).joinpath('bundles') + bundles_path.mkdir(exist_ok=True) + + # delete all bundles + for js_file in bundles_path.glob('*.js'): + js_file.unlink() + + # generate bundles + for theme in themes: + modules: Dict[str, str] = {} + + for plugin in plugins: + js_deps = [dep.path for dep in plugin.js_dependencies if theme in dep.themes] + if js_deps: + js = '' + for path in js_deps: + with open(os.path.join(static_path, path), encoding='utf-8') as s: + # We wrap the code in a self-calling function to prevent + # namespace collisions between scripts. + js += f'/** {path} **/\n(function(){{\n{s.read()}\n}})();' + + modules[plugin.id] = js + + for i in range(1, len(modules) + 1): + for plugin_combination in itertools.combinations(modules, i): + with bundles_path.joinpath(_bundle_path(theme, plugin_combination)).open('w', encoding='utf-8') as f: + js = '' + for plugin in plugin_combination: + js += f'/**** {plugin} ****/\n' + modules[plugin] + f.write(js) + + +def get_bundle_url(theme: str, plugins: Iterable[Plugin]): + plugin_ids = [p.id for p in plugins if any(dep for dep in p.js_dependencies if theme in dep.themes)] + if plugin_ids: + return url_for('static', filename='bundles/' + _bundle_path(theme, sorted(plugin_ids))) + else: + return None + + +def _bundle_path(theme: str, sorted_plugin_ids: Iterable[str]): + return theme + '+' + '+'.join(sorted_plugin_ids) + '.js' diff --git a/searx/templates/oscar/base.html b/searx/templates/oscar/base.html index de7d05bf6..6b31737fd 100644 --- a/searx/templates/oscar/base.html +++ b/searx/templates/oscar/base.html @@ -101,9 +101,9 @@ data-method="{{ method or 'POST' }}" data-autocompleter="{% if autocomplete %}true{% else %}false{% endif %}" data-translations="{{ translations }}"> - {% for script in scripts %} - {{""}} - {% endfor %} + {% if plugin_scripts_bundle_url %} + + {% endif %}