diff --git a/dev/devguides/dependency_mgmt/index.html b/dev/devguides/dependency_mgmt/index.html index f990304e..2deb4c78 100644 --- a/dev/devguides/dependency_mgmt/index.html +++ b/dev/devguides/dependency_mgmt/index.html @@ -74,10 +74,10 @@ <!-- _RENDERED "button_309dcf,31c0da" --> <button>Click me!</button>
Each <!-- _RENDERED -->
comment includes comma-separated data - a unique hash for the component class, e.g. my_table_10bc2c
, and the component ID, e.g. c020ad
.
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 <!-- _RENDERED -->
comments remain in the rendered string, we will be able to deduce which JS and CSS dependencies the component needs.
<!-- _RENDERED -->
comments, and instead inserting the corresponding JS and CSS dependencies.If we dealt only with JS, then we could get away with processing the <!-- _RENDERED -->
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 <style>
or <link>
HTML tags. Because if we do not do that, we get a flash of unstyled content, as there will be a delay between when the HTML page loaded and when the CSS was fetched and loaded.
So, assuming that a user has already rendered their template, which still contains <!-- _RENDERED -->
comments, we need to extract and process these comments.
There's multiple ways to achieve this:
The approach recommended to the users is to use the ComponentDependencyMiddleware
middleware, which scans all outgoing HTML, and post-processes the <!-- _RENDERED -->
comments.
If users are using Component.render()
or Component.render_to_response()
, these post-process the <!-- _RENDERED -->
comments by default.
render_dependencies=False
.For advanced use cases, users may use render_dependencies()
directly. This is the function that both ComponentDependencyMiddleware
and Component.render()
call internally.
render_dependencies()
, whether called directly, via middleware or other way, does the following:
Find all <!-- _RENDERED -->
comments, and for each comment:
Look up the corresponding component class.
Get the component's inlined JS / CSS from Component.js/css
, and linked JS / CSS from Component.Media.js/css
.
Generate JS script that loads the JS / CSS dependencies.
Insert the JS scripts either at the end of <body>
, or in place of {% component_dependencies %}
/ {% component_js_dependencies %}
tags.
To avoid the flash of unstyled content, 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 <head>
, or in place of {% component_dependencies %}
/ {% component_css_dependencies %}
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 Component.Media.js/css
.
Server returns the post-processed HTML.
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 <script>
or <link>
HTML tags to load the JS / CSS dependencies.
In the browser, the "dependency manager JS" may look like this:
// Load JS or CSS script if not loaded already
-Components.loadScript("js", '<script src="/abc/xyz/script.js">');
-Components.loadScript("css", '<link href="/abc/xyz/style.css">');
+Components.loadJs('<script src="/abc/xyz/script.js">');
+Components.loadCss('<link href="/abc/xyz/style.css">');
// Or mark one as already-loaded, so it is ignored when
-// we call `loadScript`
+// we call `loadJs`
Components.markScriptLoaded("js", "/abc/def");
-
Note that loadScript()
receives a whole <script>
and <link>
tags, not just the URL. This is because when Django's Media
class renders JS and CSS, it formats it as <script>
and <link>
tags. And we allow users to modify how the JS and CSS should be rendered into the <script>
and <link>
tags.
So, if users decided to add an extra attribute to their <script>
tags, e.g. <script defer src="http://..."></script>
, then this way we make sure that the defer
attribute will be present on the <script>
tag when it is inserted into the DOM at the time of loading the JS script.
/components/cache/<str:comp_cls_hash>.<str:script_type>/
E.g. /components/cache/my_table_10bc2c.js/
This endpoint takes the component's unique hash, e.g. my_table_10bc2c
, and looks up the component's inlined JS or CSS.
Thus, with this approach, we ensure that: