mirror of
https://github.com/django-components/django-components.git
synced 2025-08-18 13:10:13 +00:00
83 lines
No EOL
63 KiB
HTML
83 lines
No EOL
63 KiB
HTML
<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=description content="A way to create simple reusable template components in Django."><link href=https://emilstenstrom.github.io/django-components/latest/devguides/dependency_mgmt/ rel=canonical><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.5.43"><title>JS and CSS rendering - Django-Components</title><link rel=stylesheet href=../../assets/stylesheets/main.0253249f.min.css><link rel=stylesheet href=../../assets/stylesheets/palette.06af60db.min.css><link rel=preconnect href=https://fonts.gstatic.com crossorigin><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback"><style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style><link rel=stylesheet href=../../assets/_markdown_exec_pyodide.css><link rel=stylesheet href=../../assets/_mkdocstrings.css><link rel=stylesheet href=../../css/timeago.css><script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script><meta property=og:type content=website><meta property=og:title content="JS and CSS rendering - Django-Components"><meta property=og:description content="A way to create simple reusable template components in Django."><meta property=og:image content=https://emilstenstrom.github.io/django-components/latest/assets/images/social/devguides/dependency_mgmt.png><meta property=og:image:type content=image/png><meta property=og:image:width content=1200><meta property=og:image:height content=630><meta content=https://emilstenstrom.github.io/django-components/latest/devguides/dependency_mgmt/ property=og:url><meta name=twitter:card content=summary_large_image><meta name=twitter:title content="JS and CSS rendering - Django-Components"><meta name=twitter:description content="A way to create simple reusable template components in Django."><meta name=twitter:image content=https://emilstenstrom.github.io/django-components/latest/assets/images/social/devguides/dependency_mgmt.png></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#js-and-css-rendering class=md-skip> Skip to content </a> </div> <div data-md-component=announce> <aside class=md-banner> <div class="md-banner__inner md-grid md-typeset"> 🚨The documentation is still a work in progress. 🚨 </div> </aside> </div> <div data-md-color-scheme=default data-md-component=outdated hidden> </div> <header class="md-header md-header--shadow" data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../.. title=Django-Components class="md-header__button md-logo" aria-label=Django-Components data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> Django-Components </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> JS and CSS rendering </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media=(prefers-color-scheme) data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="m14.3 16-.7-2h-3.2l-.7 2H7.8L11 7h2l3.2 9zM20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12zm-9.15 3.96h2.3L12 9z"/></svg> </label> <input class=md-option data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme=default data-md-color-primary=teal data-md-color-accent=indigo aria-label="Switch to dark mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_2 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg> </label> <input class=md-option data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme=slate data-md-color-primary=teal data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_2> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script> <label class="md-header__button md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> </label> <div class=md-search data-md-component=search role=dialog> <label class=md-search__overlay for=__search></label> <div class=md-search__inner role=search> <form class=md-search__form name=search> <input type=text class=md-search__input name=query aria-label=Search placeholder=Search autocapitalize=off autocorrect=off autocomplete=off spellcheck=false data-md-component=search-query required> <label class="md-search__icon md-icon" for=__search> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg> </label> <nav class=md-search__options aria-label=Search> <a href=javascript:void(0) class="md-search__icon md-icon" title=Share aria-label=Share data-clipboard data-clipboard-text data-md-component=search-share tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg> </a> <button type=reset class="md-search__icon md-icon" title=Clear aria-label=Clear tabindex=-1> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg> </button> </nav> <div class=md-search__suggest data-md-component=search-suggest></div> </form> <div class=md-search__output> <div class=md-search__scrollwrap tabindex=0 data-md-scrollfix> <div class=md-search-result data-md-component=search-result> <div class=md-search-result__meta> Initializing search </div> <ol class=md-search-result__list role=presentation></ol> </div> </div> </div> </div> </div> <div class=md-header__source> <a href=https://github.com/EmilStenstrom/django-components title="Go to repository" class=md-source data-md-component=source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 496 512"><!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> EmilStenstrom/django-components </div> </a> </div> </nav> </header> <div class=md-container data-md-component=container> <main class=md-main data-md-component=main> <div class="md-main__inner md-grid"> <div class="md-sidebar md-sidebar--primary" data-md-component=sidebar data-md-type=navigation> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--primary" aria-label=Navigation data-md-level=0> <label class=md-nav__title for=__drawer> <a href=../.. title=Django-Components class="md-nav__button md-logo" aria-label=Django-Components data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> Django-Components </label> <div class=md-nav__source> <a href=https://github.com/EmilStenstrom/django-components title="Go to repository" class=md-source data-md-component=source> <div class="md-source__icon md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 496 512"><!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </div> <div class=md-source__repository> EmilStenstrom/django-components </div> </a> </div> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_1> <div class="md-nav__link md-nav__container"> <a href=../.. class="md-nav__link "> <span class=md-ellipsis> README </span> </a> <label class="md-nav__link " for=__nav_1 id=__nav_1_label tabindex> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_1_label aria-expanded=false> <label class=md-nav__title for=__nav_1> <span class="md-nav__icon md-icon"></span> README </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../CHANGELOG/ class=md-nav__link> <span class=md-ellipsis> Changelog </span> </a> </li> <li class=md-nav__item> <a href=../../CODE_OF_CONDUCT/ class=md-nav__link> <span class=md-ellipsis> Code of Conduct </span> </a> </li> <li class=md-nav__item> <a href=../../license/ class=md-nav__link> <span class=md-ellipsis> License </span> </a> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--section md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2> <label class=md-nav__link for=__nav_2 id=__nav_2_label tabindex> <span class=md-ellipsis> Reference </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=1 aria-labelledby=__nav_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2> <span class="md-nav__icon md-icon"></span> Reference </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1> <label class=md-nav__link for=__nav_2_1 id=__nav_2_1_label tabindex=0> <span class=md-ellipsis> API Reference </span> <span class="md-nav__icon md-icon"></span> </label> <nav class=md-nav data-md-level=2 aria-labelledby=__nav_2_1_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1> <span class="md-nav__icon md-icon"></span> API Reference </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_1> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> django_components </span> </a> <label class="md-nav__link " for=__nav_2_1_1 id=__nav_2_1_1_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=3 aria-labelledby=__nav_2_1_1_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_1> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> django_components </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../reference/django_components/app_settings/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> app_settings </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/apps/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> apps </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/attributes/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> attributes </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/autodiscovery/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> autodiscovery </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/component/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> component </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/component_media/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> component_media </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/component_registry/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> component_registry </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_1_9> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components/components/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> components </span> </a> <label class="md-nav__link " for=__nav_2_1_1_9 id=__nav_2_1_1_9_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=4 aria-labelledby=__nav_2_1_1_9_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_1_9> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> components </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../reference/django_components/components/dynamic/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> dynamic </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../reference/django_components/context/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> context </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/dependencies/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> dependencies </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/expression/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> expression </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/finders/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> finders </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/library/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> library </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_1_15> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components/management/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> management </span> </a> <label class="md-nav__link " for=__nav_2_1_1_15 id=__nav_2_1_1_15_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=4 aria-labelledby=__nav_2_1_1_15_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_1_15> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> management </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_1_15_2> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components/management/commands/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> commands </span> </a> <label class="md-nav__link " for=__nav_2_1_1_15_2 id=__nav_2_1_1_15_2_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=5 aria-labelledby=__nav_2_1_1_15_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_1_15_2> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> commands </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../reference/django_components/management/commands/startcomponent/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> startcomponent </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/management/commands/upgradecomponent/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> upgradecomponent </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../reference/django_components/middleware/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> middleware </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/node/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> node </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/provide/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> provide </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/slots/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> slots </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/tag_formatter/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> tag_formatter </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/template/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> template </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/template_loader/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> template_loader </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/template_parser/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> template_parser </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_1_24> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components/templatetags/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> templatetags </span> </a> <label class="md-nav__link " for=__nav_2_1_1_24 id=__nav_2_1_1_24_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=4 aria-labelledby=__nav_2_1_1_24_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_1_24> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> templatetags </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../reference/django_components/templatetags/component_tags/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> component_tags </span> </a> </li> </ul> </nav> </li> <li class=md-nav__item> <a href=../../reference/django_components/types/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> types </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/urls/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> urls </span> </a> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_1_27> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components/util/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> util </span> </a> <label class="md-nav__link " for=__nav_2_1_1_27 id=__nav_2_1_1_27_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=4 aria-labelledby=__nav_2_1_1_27_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_1_27> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> util </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../reference/django_components/util/cache/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> cache </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/html/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> html </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/loader/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> loader </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/logger/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> logger </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/misc/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> misc </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/nanoid/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> nanoid </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/tag_parser/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> tag_parser </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/types/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> types </span> </a> </li> <li class=md-nav__item> <a href=../../reference/django_components/util/validation/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> validation </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_2> <div class="md-nav__link md-nav__container"> <a href=../../reference/django_components_js/build/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> django_components_js </span> </a> </div> <nav class=md-nav data-md-level=3 aria-labelledby=__nav_2_1_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_2> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> django_components_js </label> <ul class=md-nav__list data-md-scrollfix> </ul> </nav> </li> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_3> <div class="md-nav__link md-nav__container"> <a href=../../reference/docs/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> docs </span> </a> <label class="md-nav__link " for=__nav_2_1_3 id=__nav_2_1_3_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=3 aria-labelledby=__nav_2_1_3_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_3> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> docs </label> <ul class=md-nav__list data-md-scrollfix> <li class="md-nav__item md-nav__item--nested"> <input class="md-nav__toggle md-toggle md-toggle--indeterminate" type=checkbox id=__nav_2_1_3_2> <div class="md-nav__link md-nav__container"> <a href=../../reference/docs/scripts/ class="md-nav__link "> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> scripts </span> </a> <label class="md-nav__link " for=__nav_2_1_3_2 id=__nav_2_1_3_2_label tabindex=0> <span class="md-nav__icon md-icon"></span> </label> </div> <nav class=md-nav data-md-level=4 aria-labelledby=__nav_2_1_3_2_label aria-expanded=false> <label class=md-nav__title for=__nav_2_1_3_2> <span class="md-nav__icon md-icon"></span> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> scripts </label> <ul class=md-nav__list data-md-scrollfix> <li class=md-nav__item> <a href=../../reference/docs/scripts/reference/ class=md-nav__link> <span class=md-ellipsis> <code class="doc-symbol doc-symbol-nav doc-symbol-module"></code> reference </span> </a> </li> </ul> </nav> </li> </ul> </nav> </li> </ul> </nav> </li> </ul> </nav> </li> </ul> </nav> </div> </div> </div> <div class="md-sidebar md-sidebar--secondary" data-md-component=sidebar data-md-type=toc> <div class=md-sidebar__scrollwrap> <div class=md-sidebar__inner> <nav class="md-nav md-nav--secondary" aria-label="Table of contents"> <label class=md-nav__title for=__toc> <span class="md-nav__icon md-icon"></span> Table of contents </label> <ul class=md-nav__list data-md-component=toc data-md-scrollfix> <li class=md-nav__item> <a href=#starting-conditions class=md-nav__link> <span class=md-ellipsis> Starting conditions </span> </a> </li> <li class=md-nav__item> <a href=#flow class=md-nav__link> <span class=md-ellipsis> Flow </span> </a> </li> </ul> </nav> </div> </div> </div> <div class=md-content data-md-component=content> <article class="md-content__inner md-typeset"> <a href=https://github.com/EmilStenstrom/django-components/edit/master/src/docs/devguides/dependency_mgmt.md title="Edit this page" class="md-content__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg> </a> <a href=https://github.com/EmilStenstrom/django-components/raw/master/src/docs/devguides/dependency_mgmt.md title="View source of this page" class="md-content__button md-icon"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg> </a> <h1 id=js-and-css-rendering>JS and CSS rendering<a class=headerlink href=#js-and-css-rendering title="Permanent link">¤</a></h1> <p>Aim of this doc is to share the intuition on how we manage the JS and CSS ("dependencies") associated with components, and how we render them.</p> <h2 id=starting-conditions>Starting conditions<a class=headerlink href=#starting-conditions title="Permanent link">¤</a></h2> <ol> <li>First of all, when we consider a component, it has two kind of dependencies - the "inlined" JS and CSS, and additional linked JS and CSS via <code>Media.js/css</code>:</li> </ol> <div class=highlight><pre><span></span><code><a id=__codelineno-0-1 name=__codelineno-0-1 href=#__codelineno-0-1></a><span class=kn>from</span> <span class=nn>django_components</span> <span class=kn>import</span> <span class=n>Component</span><span class=p>,</span> <span class=n>types</span>
|
|
<a id=__codelineno-0-2 name=__codelineno-0-2 href=#__codelineno-0-2></a>
|
|
<a id=__codelineno-0-3 name=__codelineno-0-3 href=#__codelineno-0-3></a><span class=k>class</span> <span class=nc>MyTable</span><span class=p>(</span><span class=n>Component</span><span class=p>):</span>
|
|
<a id=__codelineno-0-4 name=__codelineno-0-4 href=#__codelineno-0-4></a> <span class=c1># Inlined JS</span>
|
|
<a id=__codelineno-0-5 name=__codelineno-0-5 href=#__codelineno-0-5></a> <span class=n>js</span><span class=p>:</span> <span class=n>types</span><span class=o>.</span><span class=n>js</span> <span class=o>=</span> <span class=s2>"""</span>
|
|
<a id=__codelineno-0-6 name=__codelineno-0-6 href=#__codelineno-0-6></a><span class=s2> console.log(123);</span>
|
|
<a id=__codelineno-0-7 name=__codelineno-0-7 href=#__codelineno-0-7></a><span class=s2> """</span>
|
|
<a id=__codelineno-0-8 name=__codelineno-0-8 href=#__codelineno-0-8></a>
|
|
<a id=__codelineno-0-9 name=__codelineno-0-9 href=#__codelineno-0-9></a> <span class=c1># Inlined CSS</span>
|
|
<a id=__codelineno-0-10 name=__codelineno-0-10 href=#__codelineno-0-10></a> <span class=n>css</span><span class=p>:</span> <span class=n>types</span><span class=o>.</span><span class=n>css</span> <span class=o>=</span> <span class=s2>"""</span>
|
|
<a id=__codelineno-0-11 name=__codelineno-0-11 href=#__codelineno-0-11></a><span class=s2> .my-table {</span>
|
|
<a id=__codelineno-0-12 name=__codelineno-0-12 href=#__codelineno-0-12></a><span class=s2> color: red;</span>
|
|
<a id=__codelineno-0-13 name=__codelineno-0-13 href=#__codelineno-0-13></a><span class=s2> }</span>
|
|
<a id=__codelineno-0-14 name=__codelineno-0-14 href=#__codelineno-0-14></a><span class=s2> """</span>
|
|
<a id=__codelineno-0-15 name=__codelineno-0-15 href=#__codelineno-0-15></a>
|
|
<a id=__codelineno-0-16 name=__codelineno-0-16 href=#__codelineno-0-16></a> <span class=c1># Linked JS / CSS</span>
|
|
<a id=__codelineno-0-17 name=__codelineno-0-17 href=#__codelineno-0-17></a> <span class=k>class</span> <span class=nc>Media</span><span class=p>:</span>
|
|
<a id=__codelineno-0-18 name=__codelineno-0-18 href=#__codelineno-0-18></a> <span class=n>js</span> <span class=o>=</span> <span class=p>[</span>
|
|
<a id=__codelineno-0-19 name=__codelineno-0-19 href=#__codelineno-0-19></a> <span class=s2>"script-one.js"</span><span class=p>,</span> <span class=c1># STATIC file relative to component file</span>
|
|
<a id=__codelineno-0-20 name=__codelineno-0-20 href=#__codelineno-0-20></a> <span class=s2>"/script-two.js"</span><span class=p>,</span> <span class=c1># URL path</span>
|
|
<a id=__codelineno-0-21 name=__codelineno-0-21 href=#__codelineno-0-21></a> <span class=s2>"https://example.com/script-three.js"</span><span class=p>,</span> <span class=c1># URL</span>
|
|
<a id=__codelineno-0-22 name=__codelineno-0-22 href=#__codelineno-0-22></a> <span class=p>]</span>
|
|
<a id=__codelineno-0-23 name=__codelineno-0-23 href=#__codelineno-0-23></a>
|
|
<a id=__codelineno-0-24 name=__codelineno-0-24 href=#__codelineno-0-24></a> <span class=n>css</span> <span class=o>=</span> <span class=p>[</span>
|
|
<a id=__codelineno-0-25 name=__codelineno-0-25 href=#__codelineno-0-25></a> <span class=s2>"style-one.css"</span><span class=p>,</span> <span class=c1># STATIC file relative to component file</span>
|
|
<a id=__codelineno-0-26 name=__codelineno-0-26 href=#__codelineno-0-26></a> <span class=s2>"/style-two.css"</span><span class=p>,</span> <span class=c1># URL path</span>
|
|
<a id=__codelineno-0-27 name=__codelineno-0-27 href=#__codelineno-0-27></a> <span class=s2>"https://example.com/style-three.css"</span><span class=p>,</span> <span class=c1># URL</span>
|
|
<a id=__codelineno-0-28 name=__codelineno-0-28 href=#__codelineno-0-28></a> <span class=p>]</span>
|
|
</code></pre></div> <ol> <li>Second thing to keep in mind is that all component's are eventually rendered into a string. And so, if we want to associate extra info with a rendered component, it has to be serialized to a string.</li> </ol> <p>This is because a component may be embedded in a Django Template with the <code>{% component %}</code> tag, which, when rendered, is turned into a string:</p> <div class=highlight><pre><span></span><code><a id=__codelineno-1-1 name=__codelineno-1-1 href=#__codelineno-1-1></a><span class=n>template</span> <span class=o>=</span> <span class=n>Template</span><span class=p>(</span><span class=s2>"""</span>
|
|
<a id=__codelineno-1-2 name=__codelineno-1-2 href=#__codelineno-1-2></a><span class=s2> {</span><span class=si>% lo</span><span class=s2>ad component_tags %}</span>
|
|
<a id=__codelineno-1-3 name=__codelineno-1-3 href=#__codelineno-1-3></a><span class=s2> <div></span>
|
|
<a id=__codelineno-1-4 name=__codelineno-1-4 href=#__codelineno-1-4></a><span class=s2> {</span><span class=si>% c</span><span class=s2>omponent "my_table" / %}</span>
|
|
<a id=__codelineno-1-5 name=__codelineno-1-5 href=#__codelineno-1-5></a><span class=s2> </div></span>
|
|
<a id=__codelineno-1-6 name=__codelineno-1-6 href=#__codelineno-1-6></a><span class=s2>"""</span><span class=p>)</span>
|
|
<a id=__codelineno-1-7 name=__codelineno-1-7 href=#__codelineno-1-7></a>
|
|
<a id=__codelineno-1-8 name=__codelineno-1-8 href=#__codelineno-1-8></a><span class=n>html_str</span> <span class=o>=</span> <span class=n>template</span><span class=o>.</span><span class=n>render</span><span class=p>(</span><span class=n>Context</span><span class=p>({}))</span>
|
|
</code></pre></div> <p>And for this reason, we take the same approach also when we render a component with <code>Component.render()</code> - It returns a string.</p> <ol> <li>Thirdly, we also want to add support for JS / CSS variables. That is, that a variable defined on the component would be somehow accessible from within the JS script / CSS style.</li> </ol> <p>A simple approach to this would be to modify the inlined JS / CSS directly, and insert them for each component. But if you had extremely large JS / CSS, and e.g. only a single JS / CSS variable that you want to insert, it would be extremely wasteful to copy-paste the JS / CSS for each component instance.</p> <p>So instead, a preferred approach here is to defined and insert the inlined JS / CSS only once, and have some kind of mechanism on how we make correct the JS / CSS variables available only to the correct components.</p> <ol> <li>Last important thing is that we want the JS / CSS dependencies to work also with HTML fragments.</li> </ol> <p>So normally, e.g. when a user hits URL of a web page, the server renders full HTML document, with <code><!doctype></code>, <code><html></code>, <code><head></code>, and <code><body></code>. In such case, we know about ALL JS and CSS dependencies at render time, so we can e.g. insert them into <code><head></code> and <code><body></code> ourselves.</p> <p>However this renders only the initial state. HTML fragments is a common pattern where interactivity is added to the web page by fetching and replacing bits of HTML on the main HTML document after some user action.</p> <p>In the case of HTML fragments, the HTML is NOT a proper document, but only the HTML that will be inserted somewhere into the DOM.</p> <p>The challenge here is that Django template for the HTML fragment MAY contain components, and these components MAY have inlined or linked JS and CSS.</p> <div class=highlight><pre><span></span><code><a id=__codelineno-2-1 name=__codelineno-2-1 href=#__codelineno-2-1></a><span class=k>def</span> <span class=nf>fragment_view</span><span class=p>(</span><span class=n>request</span><span class=p>):</span>
|
|
<a id=__codelineno-2-2 name=__codelineno-2-2 href=#__codelineno-2-2></a> <span class=n>template</span> <span class=o>=</span> <span class=n>Template</span><span class=p>(</span><span class=s2>"""</span>
|
|
<a id=__codelineno-2-3 name=__codelineno-2-3 href=#__codelineno-2-3></a><span class=s2> {</span><span class=si>% lo</span><span class=s2>ad component_tags %}</span>
|
|
<a id=__codelineno-2-4 name=__codelineno-2-4 href=#__codelineno-2-4></a><span class=s2> <div></span>
|
|
<a id=__codelineno-2-5 name=__codelineno-2-5 href=#__codelineno-2-5></a><span class=s2> {</span><span class=si>% c</span><span class=s2>omponent "my_table" / %}</span>
|
|
<a id=__codelineno-2-6 name=__codelineno-2-6 href=#__codelineno-2-6></a><span class=s2> </div></span>
|
|
<a id=__codelineno-2-7 name=__codelineno-2-7 href=#__codelineno-2-7></a><span class=s2> """</span><span class=p>)</span>
|
|
<a id=__codelineno-2-8 name=__codelineno-2-8 href=#__codelineno-2-8></a>
|
|
<a id=__codelineno-2-9 name=__codelineno-2-9 href=#__codelineno-2-9></a> <span class=n>fragment_str</span> <span class=o>=</span> <span class=n>template</span><span class=o>.</span><span class=n>render</span><span class=p>(</span><span class=n>Context</span><span class=p>({}))</span>
|
|
<a id=__codelineno-2-10 name=__codelineno-2-10 href=#__codelineno-2-10></a> <span class=k>return</span> <span class=n>HttpResponse</span><span class=p>(</span><span class=n>fragment_str</span><span class=p>,</span> <span class=n>status</span><span class=o>=</span><span class=mi>200</span><span class=p>)</span>
|
|
</code></pre></div> <p>User may use different libraries to fetch and insert the HTML fragments (e.g. HTMX, AlpineJS, ...). From our perspective, the only thing that we can reliably say is that we expect that the HTML fragment WILL be eventually inserted into the DOM.</p> <p>So to include the corresponding JS and CSS, a simple approach could be to append them to the HTML as <code><style></code> and <code><script></code>, e.g.:</p> <div class=highlight><pre><span></span><code><a id=__codelineno-3-1 name=__codelineno-3-1 href=#__codelineno-3-1></a><span class=cm><!-- Original content --></span>
|
|
<a id=__codelineno-3-2 name=__codelineno-3-2 href=#__codelineno-3-2></a><span class=p><</span><span class=nt>div</span><span class=p>></span>...<span class=p></</span><span class=nt>div</span><span class=p>></span>
|
|
<a id=__codelineno-3-3 name=__codelineno-3-3 href=#__codelineno-3-3></a><span class=cm><!-- Associated CSS files --></span>
|
|
<a id=__codelineno-3-4 name=__codelineno-3-4 href=#__codelineno-3-4></a><span class=p><</span><span class=nt>link</span> <span class=na>href</span><span class=o>=</span><span class=s>"http://..."</span> <span class=p>/></span>
|
|
<a id=__codelineno-3-5 name=__codelineno-3-5 href=#__codelineno-3-5></a><span class=p><</span><span class=nt>style</span><span class=p>></span>
|
|
<a id=__codelineno-3-6 name=__codelineno-3-6 href=#__codelineno-3-6></a><span class=w> </span><span class=p>.</span><span class=nc>my-class</span><span class=w> </span><span class=p>{</span>
|
|
<a id=__codelineno-3-7 name=__codelineno-3-7 href=#__codelineno-3-7></a><span class=w> </span><span class=k>color</span><span class=p>:</span><span class=w> </span><span class=kc>red</span><span class=p>;</span>
|
|
<a id=__codelineno-3-8 name=__codelineno-3-8 href=#__codelineno-3-8></a><span class=w> </span><span class=p>}</span>
|
|
<a id=__codelineno-3-9 name=__codelineno-3-9 href=#__codelineno-3-9></a><span class=p></</span><span class=nt>style</span><span class=p>></span>
|
|
<a id=__codelineno-3-10 name=__codelineno-3-10 href=#__codelineno-3-10></a><span class=cm><!-- Associated JS files --></span>
|
|
<a id=__codelineno-3-11 name=__codelineno-3-11 href=#__codelineno-3-11></a><span class=p><</span><span class=nt>script</span> <span class=na>src</span><span class=o>=</span><span class=s>"http://..."</span><span class=p>></</span><span class=nt>script</span><span class=p>></span>
|
|
<a id=__codelineno-3-12 name=__codelineno-3-12 href=#__codelineno-3-12></a><span class=p><</span><span class=nt>script</span><span class=p>></span>
|
|
<a id=__codelineno-3-13 name=__codelineno-3-13 href=#__codelineno-3-13></a><span class=w> </span><span class=nx>console</span><span class=p>.</span><span class=nx>log</span><span class=p>(</span><span class=mf>123</span><span class=p>);</span>
|
|
<a id=__codelineno-3-14 name=__codelineno-3-14 href=#__codelineno-3-14></a><span class=p></</span><span class=nt>script</span><span class=p>></span>
|
|
</code></pre></div> <p>But this has a number of issues:</p> <ul> <li>The JS scripts would run for each instance of the component.</li> <li>Bloating of the HTML file, as each inlined JS or CSS would be included fully for each component.<ul> <li>While this sound OK, this could really bloat the HTML files if we used a UI component library for the basic building blocks like buttons, lists, cards, etc.</li> </ul> </li> </ul> <h2 id=flow>Flow<a class=headerlink href=#flow title="Permanent link">¤</a></h2> <p>So the solution should address all the points above. To achieve that, we manage the JS / CSS dependencies ourselves in the browser. So when a full HTML document is loaded, we keep track of which JS and CSS have been loaded. And when an HTML fragment is inserted, we check which JS / CSS dependencies it has, and load only those that have NOT been loaded yet.</p> <p>This is how we achieve that:</p> <ol> <li>When a component is rendered, it inserts an HTML comment containing metadata about the rendered component.</li> </ol> <p>So a template like this</p> <div class=highlight><pre><span></span><code><a id=__codelineno-4-1 name=__codelineno-4-1 href=#__codelineno-4-1></a><span class=cp>{%</span> <span class=k>load</span> <span class=nv>component_tags</span> <span class=cp>%}</span>
|
|
<a id=__codelineno-4-2 name=__codelineno-4-2 href=#__codelineno-4-2></a><span class=x><div></span>
|
|
<a id=__codelineno-4-3 name=__codelineno-4-3 href=#__codelineno-4-3></a><span class=x> </span><span class=cp>{%</span> <span class=k>component</span> <span class=s2>"my_table"</span> <span class=o>/</span> <span class=cp>%}</span>
|
|
<a id=__codelineno-4-4 name=__codelineno-4-4 href=#__codelineno-4-4></a><span class=x></div></span>
|
|
<a id=__codelineno-4-5 name=__codelineno-4-5 href=#__codelineno-4-5></a><span class=cp>{%</span> <span class=k>component</span> <span class=s2>"button"</span> <span class=cp>%}</span>
|
|
<a id=__codelineno-4-6 name=__codelineno-4-6 href=#__codelineno-4-6></a><span class=x> Click me!</span>
|
|
<a id=__codelineno-4-7 name=__codelineno-4-7 href=#__codelineno-4-7></a><span class=cp>{%</span> <span class=k>endcomponent</span> <span class=cp>%}</span>
|
|
</code></pre></div> <p>May actually render:</p> <div class=highlight><pre><span></span><code><a id=__codelineno-5-1 name=__codelineno-5-1 href=#__codelineno-5-1></a><span class=p><</span><span class=nt>div</span><span class=p>></span>
|
|
<a id=__codelineno-5-2 name=__codelineno-5-2 href=#__codelineno-5-2></a> <span class=cm><!-- _RENDERED "my_table_10bc2c,c020ad" --></span>
|
|
<a id=__codelineno-5-3 name=__codelineno-5-3 href=#__codelineno-5-3></a> <span class=p><</span><span class=nt>table</span><span class=p>></span>
|
|
<a id=__codelineno-5-4 name=__codelineno-5-4 href=#__codelineno-5-4></a> ...
|
|
<a id=__codelineno-5-5 name=__codelineno-5-5 href=#__codelineno-5-5></a> <span class=p></</span><span class=nt>table</span><span class=p>></span>
|
|
<a id=__codelineno-5-6 name=__codelineno-5-6 href=#__codelineno-5-6></a><span class=p></</span><span class=nt>div</span><span class=p>></span>
|
|
<a id=__codelineno-5-7 name=__codelineno-5-7 href=#__codelineno-5-7></a><span class=cm><!-- _RENDERED "button_309dcf,31c0da" --></span>
|
|
<a id=__codelineno-5-8 name=__codelineno-5-8 href=#__codelineno-5-8></a><span class=p><</span><span class=nt>button</span><span class=p>></span>Click me!<span class=p></</span><span class=nt>button</span><span class=p>></span>
|
|
</code></pre></div> <p>Each <code><!-- _RENDERED --></code> comment includes comma-separated data - a unique hash for the component class, e.g. <code>my_table_10bc2c</code>, and the component ID, e.g. <code>c020ad</code>.</p> <p>This way, we or the user can freely pass the rendered around or transform it, treating it as a string to add / remove / replace bits. As long as the <code><!-- _RENDERED --></code> comments remain in the rendered string, we will be able to deduce which JS and CSS dependencies the component needs.</p> <ol> <li>Post-process the rendered HTML, extracting the <code><!-- _RENDERED --></code> comments, and instead inserting the corresponding JS and CSS dependencies.</li> </ol> <p>If we dealt only with JS, then we could get away with processing the <code><!-- _RENDERED --></code> comments on the client (browser). However, the CSS needs to be processed still on the server, so the browser receives CSS styles already inserted as <code><style></code> or <code><link></code> HTML tags. Because if we do not do that, we get a <a href=https://en.wikipedia.org/wiki/Flash_of_unstyled_content>flash of unstyled content</a>, as there will be a delay between when the HTML page loaded and when the CSS was fetched and loaded.</p> <p>So, assuming that a user has already rendered their template, which still contains <code><!-- _RENDERED --></code> comments, we need to extract and process these comments.</p> <p>There's multiple ways to achieve this:</p> <ul> <li> <p>The approach recommended to the users is to use the <code>ComponentDependencyMiddleware</code> middleware, which scans all outgoing HTML, and post-processes the <code><!-- _RENDERED --></code> comments.</p> </li> <li> <p>If users are using <code>Component.render()</code> or <code>Component.render_to_response()</code>, these post-process the <code><!-- _RENDERED --></code> comments by default.</p> <ul> <li>NOTE: Users are able to opt out of the post-processing by setting <code>render_dependencies=False</code>.</li> </ul> </li> <li> <p>For advanced use cases, users may use <code>render_dependencies()</code> directly. This is the function that both <code>ComponentDependencyMiddleware</code> and <code>Component.render()</code> call internally.</p> </li> </ul> <p><code>render_dependencies()</code>, whether called directly, via middleware or other way, does the following:</p> <ol> <li> <p>Find all <code><!-- _RENDERED --></code> comments, and for each comment:</p> </li> <li> <p>Look up the corresponding component class.</p> </li> <li> <p>Get the component's inlined JS / CSS from <code>Component.js/css</code>, and linked JS / CSS from <code>Component.Media.js/css</code>.</p> </li> <li> <p>Generate JS script that loads the JS / CSS dependencies.</p> </li> <li> <p>Insert the JS scripts either at the end of <code><body></code>, or in place of <code>{% component_dependencies %}</code> / <code>{% component_js_dependencies %}</code> tags.</p> </li> <li> <p>To avoid the <a href=https://en.wikipedia.org/wiki/Flash_of_unstyled_content>flash of unstyled content</a>, we need place the styles into the HTML instead of dynamically loading them from within a JS script. The CSS is placed either at the end of <code><head></code>, or in place of <code>{% component_dependencies %}</code> / <code>{% component_css_dependencies %}</code></p> </li> <li> <p>We cache the component's inlined JS and CSS, so they can be fetched via an URL, so the inlined JS / CSS an be treated the same way as the JS / CSS dependencies set in <code>Component.Media.js/css</code>.</p> <ul> <li>NOTE: While this is currently not entirely necessary, it opens up the doors for allowing plugins to post-process the inlined JS and CSS. Because after it has been post-processed, we need to store it somewhere.</li> </ul> </li> <li> <p>Server returns the post-processed HTML.</p> </li> <li> <p>In the browser, the generated JS script from step 2.4 is executed. It goes through all JS and CSS dependencies it was given. If some JS / CSS was already loaded, it is NOT fetched again. Otherwise it generates the corresponding <code><script></code> or <code><link></code> HTML tags to load the JS / CSS dependencies.</p> </li> </ol> <p>In the browser, the "dependency manager JS" may look like this:</p> <div class=highlight><pre><span></span><code><a id=__codelineno-6-1 name=__codelineno-6-1 href=#__codelineno-6-1></a><span class=c1>// Load JS or CSS script if not loaded already</span>
|
|
<a id=__codelineno-6-2 name=__codelineno-6-2 href=#__codelineno-6-2></a><span class=nx>Components</span><span class=p>.</span><span class=nx>loadScript</span><span class=p>(</span><span class=s2>"js"</span><span class=p>,</span><span class=w> </span><span class=s1>'<script src="/abc/xyz/script.js">'</span><span class=p>);</span>
|
|
<a id=__codelineno-6-3 name=__codelineno-6-3 href=#__codelineno-6-3></a><span class=nx>Components</span><span class=p>.</span><span class=nx>loadScript</span><span class=p>(</span><span class=s2>"css"</span><span class=p>,</span><span class=w> </span><span class=s1>'<link href="/abc/xyz/style.css">'</span><span class=p>);</span>
|
|
<a id=__codelineno-6-4 name=__codelineno-6-4 href=#__codelineno-6-4></a>
|
|
<a id=__codelineno-6-5 name=__codelineno-6-5 href=#__codelineno-6-5></a><span class=c1>// Or mark one as already-loaded, so it is ignored when</span>
|
|
<a id=__codelineno-6-6 name=__codelineno-6-6 href=#__codelineno-6-6></a><span class=c1>// we call `loadScript`</span>
|
|
<a id=__codelineno-6-7 name=__codelineno-6-7 href=#__codelineno-6-7></a><span class=nx>Components</span><span class=p>.</span><span class=nx>markScriptLoaded</span><span class=p>(</span><span class=s2>"js"</span><span class=p>,</span><span class=w> </span><span class=s2>"/abc/def"</span><span class=p>);</span>
|
|
</code></pre></div> <p>Note that <code>loadScript()</code> receives a whole <code><script></code> and <code><link></code> tags, not just the URL. This is because when Django's <code>Media</code> class renders JS and CSS, it formats it as <code><script></code> and <code><link></code> tags. And we allow users to modify how the JS and CSS should be rendered into the <code><script></code> and <code><link></code> tags.</p> <p>So, if users decided to add an extra attribute to their <code><script></code> tags, e.g. <code><script defer src="http://..."></script></code>, then this way we make sure that the <code>defer</code> attribute will be present on the <code><script></code> tag when it is inserted into the DOM at the time of loading the JS script.</p> <ol> <li>To be able to fetch component's inlined JS and CSS, django-components adds a URL path under:</li> </ol> <p><code>/components/cache/<str:comp_cls_hash>.<str:script_type>/</code></p> <p>E.g. <code>/components/cache/my_table_10bc2c.js/</code></p> <p>This endpoint takes the component's unique hash, e.g. <code>my_table_10bc2c</code>, and looks up the component's inlined JS or CSS.</p> <hr> <p>Thus, with this approach, we ensure that:</p> <ol> <li>All JS / CSS dependencies are loaded / executed only once.</li> <li>The approach is compatible with HTML fragments</li> <li>The approach is compatible with JS / CSS variables.</li> <li>Inlined JS / CSS may be post-processed by plugins</li> </ol> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-timeago"><span class=timeago datetime=2024-11-25T08:41:57+00:00 locale=en></span></span><span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-iso_date">2024-11-25</span> </span> <span class=md-source-file__fact> <span class=md-icon title=Contributors> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 4a4 4 0 0 1 4 4 4 4 0 0 1-4 4 4 4 0 0 1-4-4 4 4 0 0 1 4-4m0 10c4.42 0 8 1.79 8 4v2H4v-2c0-2.21 3.58-4 8-4"/></svg> </span> <nav> <a href=mailto:juraj.oravec.josefson@gmail.com>Juro Oravec</a> </nav> </span> </aside> </article> </div> <script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> Made with <a href=https://squidfunk.github.io/mkdocs-material/ target=_blank rel=noopener> Material for MkDocs </a> </div> <div class=md-social> <a href=https://github.com/EmilStenstrom/django-components target=_blank rel=noopener title=github.com class=md-social__link> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 496 512"><!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8M97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </a> <a href=https://pypi.org/project/django-components/ target=_blank rel=noopener title=pypi.org class=md-social__link> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 448 512"><!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M439.8 200.5c-7.7-30.9-22.3-54.2-53.4-54.2h-40.1v47.4c0 36.8-31.2 67.8-66.8 67.8H172.7c-29.2 0-53.4 25-53.4 54.3v101.8c0 29 25.2 46 53.4 54.3 33.8 9.9 66.3 11.7 106.8 0 26.9-7.8 53.4-23.5 53.4-54.3v-40.7H226.2v-13.6h160.2c31.1 0 42.6-21.7 53.4-54.2 11.2-33.5 10.7-65.7 0-108.6M286.2 404c11.1 0 20.1 9.1 20.1 20.3 0 11.3-9 20.4-20.1 20.4-11 0-20.1-9.2-20.1-20.4.1-11.3 9.1-20.3 20.1-20.3M167.8 248.1h106.8c29.7 0 53.4-24.5 53.4-54.3V91.9c0-29-24.4-50.7-53.4-55.6-35.8-5.9-74.7-5.6-106.8.1-45.2 8-53.4 24.7-53.4 55.6v40.7h106.9v13.6h-147c-31.1 0-58.3 18.7-66.8 54.2-9.8 40.7-10.2 66.1 0 108.6 7.6 31.6 25.7 54.2 56.8 54.2H101v-48.8c0-35.3 30.5-66.4 66.8-66.4m-6.7-142.6c-11.1 0-20.1-9.1-20.1-20.3.1-11.3 9-20.4 20.1-20.4 11 0 20.1 9.2 20.1 20.4s-9 20.3-20.1 20.3"/></svg> </a> </div> </div> </div> </footer> </div> <div class=md-dialog data-md-component=dialog> <div class="md-dialog__inner md-typeset"></div> </div> <div class=md-progress data-md-component=progress role=progressbar></div> <script id=__config type=application/json>{"base": "../..", "features": ["content.action.edit", "content.action.view", "content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.expand", "navigation.footer", "navigation.instant", "navigation.instant.progress", "navigation.indexes", "navigation.sections", "navigation.tracking", "navigation.top", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../assets/javascripts/workers/search.6ce7567c.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"alias": true, "default": ["dev"], "provider": "mike"}}</script> <script src=../../assets/javascripts/bundle.83f73b43.min.js></script> <script src=../../assets/_markdown_exec_pyodide.js></script> <script src=../../js/timeago.min.js></script> <script src=../../js/timeago_mkdocs_material.js></script> </body> </html> |