Przeglądaj źródła

Serve codehilite CSS for `ui.markdown` more efficiently (#3792)

* provide codehilite CSS via separate endpoint to enable caching

* fix some pytests
Falko Schindler 7 miesięcy temu
rodzic
commit
e47ec7aec4

+ 1 - 1
nicegui/element.py

@@ -518,7 +518,7 @@ class Element(Visibility):
             additions.append(f'text={shorten(self._text)}')
         if hasattr(self, 'content') and self.content:  # pylint: disable=no-member
             additions.append(f'content={shorten(self.content)}')  # pylint: disable=no-member
-        IGNORED_PROPS = {'loopback', 'color', 'view', 'innerHTML', 'codehilite_css'}
+        IGNORED_PROPS = {'loopback', 'color', 'view', 'innerHTML', 'codehilite_css_url'}
         additions += [
             f'{key}={shorten(value)}'
             for key, value in self._props.items()

+ 5 - 10
nicegui/elements/markdown.js

@@ -1,7 +1,10 @@
+import { loadResource } from "../../static/utils/resources.js";
+
 export default {
   template: `<div></div>`,
   async mounted() {
-    this.ensure_codehilite_css();
+    await this.$nextTick(); // NOTE: wait for window.path_prefix to be set
+    await loadResource(window.path_prefix + this.codehilite_css_url);
     if (this.use_mermaid) {
       this.mermaid = (await import("mermaid")).default;
       this.renderMermaid();
@@ -21,17 +24,9 @@ export default {
         await this.mermaid.run({ nodes: [pre.children[0]] });
       });
     },
-    ensure_codehilite_css() {
-      if (!document.querySelector(`style[data-codehilite-css]`)) {
-        const style = document.createElement("style");
-        style.setAttribute("data-codehilite-css", "");
-        style.innerHTML = this.codehilite_css;
-        document.head.appendChild(style);
-      }
-    },
   },
   props: {
-    codehilite_css: String,
+    codehilite_css_url: String,
     use_mermaid: {
       required: false,
       default: false,

+ 13 - 4
nicegui/elements/markdown.py

@@ -3,11 +3,16 @@ from functools import lru_cache
 from typing import List
 
 import markdown2
+from fastapi.responses import PlainTextResponse
 from pygments.formatters import HtmlFormatter  # pylint: disable=no-name-in-module
 
+from .. import core
+from ..version import __version__
 from .mermaid import Mermaid
 from .mixins.content_element import ContentElement
 
+CODEHILITE_CSS_URL = f'/_nicegui/{__version__}/codehilite.css'
+
 
 class Markdown(ContentElement, component='markdown.js'):
 
@@ -25,14 +30,18 @@ class Markdown(ContentElement, component='markdown.js'):
         self.extras = extras[:]
         super().__init__(content=content)
         self._classes.append('nicegui-markdown')
-        self._props['codehilite_css'] = (
-            HtmlFormatter(nobackground=True).get_style_defs('.codehilite') +
-            HtmlFormatter(nobackground=True, style='github-dark').get_style_defs('.body--dark .codehilite')
-        )
         if 'mermaid' in extras:
             self._props['use_mermaid'] = True
             self.libraries.append(Mermaid.exposed_libraries[0])
 
+        self._props['codehilite_css_url'] = CODEHILITE_CSS_URL
+        if not any(r for r in core.app.routes if getattr(r, 'path', None) == CODEHILITE_CSS_URL):
+            core.app.get(CODEHILITE_CSS_URL)(lambda: PlainTextResponse(
+                HtmlFormatter(nobackground=True).get_style_defs('.codehilite') +
+                HtmlFormatter(nobackground=True, style='github-dark').get_style_defs('.body--dark .codehilite'),
+                media_type='text/css',
+            ))
+
     def _handle_content_change(self, content: str) -> None:
         html = prepare_content(content, extras=' '.join(self.extras))
         if self._props.get('innerHTML') != html:

+ 7 - 1
tests/test_endpoint_docs.py

@@ -3,7 +3,7 @@ from typing import Set
 import pytest
 import requests
 
-from nicegui import __version__
+from nicegui import __version__, ui
 from nicegui.testing import Screen
 
 
@@ -29,8 +29,11 @@ def test_endpoint_documentation_page_only(screen: Screen):
 
 def test_endpoint_documentation_internal_only(screen: Screen):
     screen.ui_run_kwargs['endpoint_documentation'] = 'internal'
+    ui.markdown('Hey!')
+
     screen.open('/')
     assert get_openapi_paths() == {
+        f'/_nicegui/{__version__}/codehilite.css',
         f'/_nicegui/{__version__}/libraries/{{key}}',
         f'/_nicegui/{__version__}/components/{{key}}',
         f'/_nicegui/{__version__}/resources/{{key}}/{{path}}',
@@ -39,9 +42,12 @@ def test_endpoint_documentation_internal_only(screen: Screen):
 
 def test_endpoint_documentation_all(screen: Screen):
     screen.ui_run_kwargs['endpoint_documentation'] = 'all'
+    ui.markdown('Hey!')
+
     screen.open('/')
     assert get_openapi_paths() == {
         '/',
+        f'/_nicegui/{__version__}/codehilite.css',
         f'/_nicegui/{__version__}/libraries/{{key}}',
         f'/_nicegui/{__version__}/components/{{key}}',
         f'/_nicegui/{__version__}/resources/{{key}}/{{path}}',