{"result":{"depiction_url":null,"edges":{"refers":{"objects":[{"created":"2026-09-09T13:48:30Z","object_id":{"id":1457,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_development","title":"mod_development","uri":"https:\/\/zotonic.com\/id\/1457"},"seq":1000000},{"created":"2026-10-21T22:03:52Z","object_id":{"id":1301,"is_a":["text","documentation","reference","template_scomp"],"name":"doc_template_scomp_scomp_script","title":"script","uri":"https:\/\/zotonic.com\/id\/1301"},"seq":1000000}],"predicate":{"id":2409,"is_a":["meta","predicate"],"name":"refers","title":{"_type":"trans","tr":{"en":"Refers"}},"uri":"https:\/\/zotonic.com\/id\/refers"}},"relation":{"objects":[{"created":"2020-05-30T05:47:53Z","object_id":{"id":1457,"is_a":["text","documentation","reference","module"],"name":"doc_module_mod_development","title":"mod_development","uri":"https:\/\/zotonic.com\/id\/1457"},"seq":1000000}],"predicate":{"id":303,"is_a":["meta","predicate"],"name":"relation","title":{"_type":"trans","tr":{"nl":"Relatie","en":"Relation"}},"uri":"http:\/\/purl.org\/dc\/terms\/relation"}},"subject":{"objects":[{"created":"2026-09-09T13:48:30Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-09-09T13:48:30Z","object_id":{"id":2563,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_frontend_developer","title":"Frontend developer","uri":"https:\/\/zotonic.com\/id\/2563"},"seq":2},{"created":"2026-09-09T13:48:30Z","object_id":{"id":2620,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_template","title":"Template","uri":"https:\/\/zotonic.com\/id\/2620"},"seq":3},{"created":"2026-09-09T13:48:30Z","object_id":{"id":2667,"is_a":["categorization","keyword","keyword_data_type"],"name":"zotonic_topic_url","title":"URL","uri":"https:\/\/zotonic.com\/id\/2667"},"seq":4},{"created":"2026-09-09T13:48:30Z","object_id":{"id":2673,"is_a":["categorization","keyword","keyword_technology"],"name":"zotonic_topic_javascript","title":"JavaScript","uri":"https:\/\/zotonic.com\/id\/2673"},"seq":5},{"created":"2026-09-09T13:48:30Z","object_id":{"id":2688,"is_a":["categorization","keyword","keyword_quality"],"name":"zotonic_topic_performance","title":"Performance","uri":"https:\/\/zotonic.com\/id\/2688"},"seq":6}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":1372,"is_a":["text","documentation","reference","template_tag"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1372"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_template_tag_tag_lib","page_url":{"en":"https:\/\/zotonic.com\/docs\/1372\/lib","x-default":"https:\/\/zotonic.com\/docs\/1372\/lib"},"preview_url":null,"resource":{"version":4073,"pivot_location_lat":null,"title":"lib","is_authoritative":true,"body":"<aside><p>See also<\/p><p><a href=\"\/id\/doc_template_scomp_scomp_script\" class=\"doc-reference doc-reference-scomp\"><code>scomp#script<\/code><\/a>, <a href=\"javascript.md\">javascript<\/a> and <a href=\"\/id\/doc_module_mod_development\" class=\"doc-reference doc-reference-module\"><code>module#mod_development<\/code><\/a>.<\/p><\/aside>\n<p>Include CSS and JavaScript libraries, combining files of each type into a single request.<\/p>\n<p>The <code>lib<\/code> tag generates <code>&lt;link&gt;<\/code> elements for CSS and <code>&lt;script&gt;<\/code> elements for JavaScript. Filenames refer to files in module or site <code>priv\/lib<\/code> directories. CSS and JavaScript use separate requests; files of the same type retain their declaration order.<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">{% lib &quot;css\/site.css&quot; &quot;css\/components.css&quot; &quot;js\/site.js&quot; %}\n<\/code><\/pre>\n<p>The generated URLs include a checksum of the files&#39; modification times, so changing a file changes its URL. Development settings can disable bundling or minification.<\/p>\n<h2>Duplicate inclusions<\/h2>\n<p>During a render, libraries already included or queued by an earlier <code>lib<\/code> tag are filtered out. For example:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">{% lib &quot;js\/a.js&quot; &quot;js\/b.js&quot; %}\n{% lib &quot;js\/b.js&quot; &quot;js\/c.js&quot; %}\n<\/code><\/pre>\n<p>The second tag includes only <code>js\/c.js<\/code>. For JavaScript, the first declaration&#39;s options take precedence. CSS declarations with different <code>media<\/code>, <code>rel<\/code> or <code>title<\/code> values are distinct inclusions.<\/p>\n<p>This tracking covers <code>lib<\/code> tags, not manually written <code>&lt;script&gt;<\/code> or <code>&lt;link&gt;<\/code> elements. Generating a URL with <code>lib_url<\/code> does not include or reserve a library and does not flush collected files.<\/p>\n<h2>Collecting libraries<\/h2>\n<p>Use <code>collect<\/code> to queue files without emitting their include elements at that position:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">{% lib &quot;js\/component.js&quot; collect %}\n\n&lt;div class=&quot;component&quot;&gt;...&lt;\/div&gt;\n\n{% lib &quot;js\/page.js&quot; %}\n<\/code><\/pre>\n<p>The last tag emits <code>component.js<\/code> before <code>page.js<\/code>, combining them when their options are compatible.<\/p>\n<p>An ordinary, non-collecting lib tag flushes only the types present in its filename list:<\/p>\n<ul><li>A CSS-only tag flushes pending CSS and leaves pending JavaScript queued.<\/li><li>A JavaScript-only tag flushes pending JavaScript and leaves pending CSS queued.<\/li><li>A mixed tag flushes both types.<\/li><\/ul>\n<p>This also applies when the ordinary tag&#39;s files are all duplicates. Another <code>collect<\/code> tag only queues files. Includes, cached render trees and <code>spaceless<\/code> blocks do not themselves flush the surrounding queue.<\/p>\n<p>Collected files retain their original options. Only adjacent compatible groups combine; declarations are not regrouped across incompatible options. CSS groups must agree on <code>media<\/code>, <code>rel<\/code> and <code>title<\/code>. Both types must have compatible loading options, effective minification, cache behavior and absolute-URL settings.<\/p>\n<p><code>collect<\/code> cannot be combined with enabled <code>async<\/code> or <code>defer<\/code>. A later ordinary tag with <code>async<\/code> or <code>defer<\/code> flushes pending files of its type first, then emits its own include separately; it does not apply those loading options to the queued files.<\/p>\n<p>Collection delays when the browser discovers the files. Intervening inline JavaScript must not depend on queued libraries, and delaying CSS can cause a flash of unstyled content.<\/p>\n<h2>Flushing libraries<\/h2>\n<p>Flush queued libraries explicitly without adding filenames:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">{% lib flush %}               {# CSS and JavaScript #}\n{% lib flush=&quot;css&quot; %}         {# CSS only #}\n{% lib flush=&quot;javascript&quot; %}  {# JavaScript only; &quot;js&quot; also works #}\n<\/code><\/pre>\n<p>Flush accepts no filenames or other options. Unknown flush values are rejected. An empty queue produces no output, and flushing does not reset duplicate tracking.<\/p>\n<p>The <a href=\"\/id\/doc_template_scomp_scomp_script\" class=\"doc-reference doc-reference-scomp\"><code>scomp#script<\/code><\/a> scomp automatically flushes both types before emitting the page&#39;s initialization script. Use an explicit CSS flush in the head when styles should load earlier:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-django\">&lt;head&gt;\n    {% lib &quot;css\/site.css&quot; collect %}\n    {% lib flush=&quot;css&quot; %}\n&lt;\/head&gt;\n&lt;body&gt;\n    {% lib &quot;js\/component.js&quot; collect %}\n    ...\n    {% script %}\n&lt;\/body&gt;\n<\/code><\/pre>\n<p>At the end of final page output, remaining collected files are emitted and a warning is logged. Use explicit flush points or <code>script<\/code> to place the include elements correctly, rather than relying on this fallback.<\/p>\n<h2>Options<\/h2>\n<p>Supply options after the filenames. Flush is an alternative form with no filenames.<\/p>\n<table class=\"table\"><thead><tr><th>Option<\/th><th>Default<\/th><th>Description<\/th><\/tr><\/thead><tbody><tr><td><code>collect<\/code><\/td><td><code>false<\/code><\/td><td>Queue files until a matching flush point. Incompatible with enabled <code>async<\/code> or <code>defer<\/code>.<\/td><\/tr><tr><td><code>flush<\/code><\/td><td>—<\/td><td>Flush both types with <code>flush<\/code>, or select <code>&quot;css&quot;<\/code>, <code>&quot;javascript&quot;<\/code> or <code>&quot;js&quot;<\/code>. Accepts no filenames or other options.<\/td><\/tr><tr><td><code>absolute_url<\/code><\/td><td><code>false<\/code><\/td><td>Generate an absolute library URL.<\/td><\/tr><tr><td><code>title<\/code><\/td><td>Unset<\/td><td>Set the CSS link&#39;s <code>title<\/code> attribute.<\/td><\/tr><tr><td><code>media<\/code><\/td><td><code>&quot;all&quot;<\/code><\/td><td>Set the CSS link&#39;s <code>media<\/code> attribute.<\/td><\/tr><tr><td><code>rel<\/code><\/td><td><code>&quot;stylesheet&quot;<\/code><\/td><td>Set the CSS link&#39;s <code>rel<\/code> attribute.<\/td><\/tr><tr><td><code>minify<\/code><\/td><td>Site setting<\/td><td>Request minification. Live reload disables minification.<\/td><\/tr><tr><td><code>nocache<\/code><\/td><td><code>false<\/code><\/td><td>Use the library route with a browser cache lifetime of at most one second.<\/td><\/tr><tr><td><code>async<\/code><\/td><td><code>false<\/code><\/td><td>Load CSS or JavaScript asynchronously. JavaScript tags also carry <code>defer<\/code> as a fallback.<\/td><\/tr><tr><td><code>defer<\/code><\/td><td><code>false<\/code><\/td><td>Load JavaScript in parallel and execute it after HTML parsing.<\/td><\/tr><\/tbody><\/table>\n<p>Set <code>site.minification_enabled<\/code> to a true value to enable minification for all lib tags. An individual <code>minify=false<\/code> does not override that site setting.<\/p>\n<h2>Dynamic updates and materialized fragments<\/h2>\n<p>Wired updates collect library dependencies separately from the HTML. The browser loads missing files before inserting the update and running its initialization JavaScript. Already loaded or loading files are shared, including individual files originally loaded in bundles. <code>collect<\/code> does not delay dependencies beyond the update, and updates wait for their libraries even when a declaration specifies <code>async<\/code> or <code>defer<\/code>.<\/p>\n<p>The template-model path <code>model\/template\/get\/render_with_assets\/&lt;template&gt;<\/code> returns <code>html<\/code>, <code>libs<\/code> and <code>javascript<\/code>. Apply this result with <code>z_assets.apply(result, insertHtml)<\/code> so the dependencies load before the insertion callback, followed by the collected JavaScript. The existing <code>render<\/code> path returns HTML only.<\/p>\n<p><code>z_template:render_to_iolist\/3<\/code> resolves collected files at the materialization boundary. Once converted to HTML, a fragment cannot be deduplicated against later fragments. Retain the render tree from <code>z_template:render\/3<\/code> when composing or caching fragments that need to share collection and duplicate tracking.<\/p>\n<p>Erlang components can guard JavaScript with library dependencies:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">Script = z_render:script_with_libs(\n    [&lt;&lt;&quot;js\/modules\/z.live.js&quot;&gt;&gt;],\n    &lt;&lt;&quot;z_live.subscribe(\/* ... *\/);&quot;&gt;&gt;,\n    Context),\nz_render:add_script(Script, Context).\n<\/code><\/pre>\n<p>The API returns JavaScript and also works in a <code>{javascript, Script}<\/code> render node.\nUse paths relative to <code>priv\/lib<\/code>, without the URL&#39;s <code>\/lib\/<\/code> prefix. Dependencies\nuse timestamped URLs and share the browser&#39;s loaded\/loading registry. The wrapped\nscript runs asynchronously after loading; put all dependent code inside it. A\nfailed load skips the script and logs the error. The <code>{% live %}<\/code> tag and MQTT\nwires use this API automatically.<\/p>","slug":"lib","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"15bc34d4ac8cdf6a0e9d090fecd89fa39b254800f2c77527ec22c7de6c792e5b","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":324,"is_a":["meta","category"],"name":"template_tag","title":"Tags","uri":"https:\/\/test.zotonic.com\/id\/324"},"doc_source_path":"doc\/template-tags\/lib.md","publication_start":"2023-06-24T08:17:56Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/doc\/template-tags\/lib.md","pivot_location_lng":null,"doc_source_kind":"template_tag","name":"doc_template_tag_tag_lib","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2020-05-30T05:47:20Z","uri":null,"doc_status":"current","is_dependent":false,"publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"7df977519c8cf191b758d30a0ddca1826a013903\n","creator_id":{"id":336,"is_a":["person","robot"],"name":"gitbot","title":"Git","uri":"https:\/\/zotonic.com\/id\/336"},"modified":"2026-10-22T13:33:48Z","title_slug":"lib"},"uri":"https:\/\/zotonic.com\/id\/1372","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1372"}},"status":"ok"}