1
0
mirror of https://github.com/snachodog/just-the-docs.git synced 2025-04-10 14:01:22 -06:00

Fix: improve build time ()

* Remove "passive" toggle

PR  introduced the "passive" toggle, but just-the-docs.js subsequently disabled the only styling that used it, so it became redundant.
This removes it.

* Reduce build time for page-dependent CSS

Fix 

- Remove `_includes/head_nav.html`.
- Generate page-independent SCSS in `assets/css/just-the-docs-head-nav.css`.
- Link to `/assets/css/just-the-docs-head-nav.css` in `head.html`.
- Disable the above stylesheet in `assets/js/just-the-docs.js`.
- Generate page-dependent CSS in `_includes/css/activation.scss.liquid` and include in `head.html`.

* No override svg rotate

* Disable both stylesheets safely

* Move the site nav to a new include

- Fix the complete site nav
- Move the site nav to `_includes/site_nav.html`
- Cache the site nav
- Uncache `nav.html`

* Move nav and site_nav to _includes/components

* Replace id prefix

* Update breadcrumbs.html

Replace several filters by a single loop through all the pages,
but breaking as soon as possible.

Profiling indicates that this saves up to 50% of the breadcrumbs build time for the filters.

* Update just-the-docs-head-nav.css

Adjust the number of lines to keep

* Update head.html

Remove superflous type.

* Update activation.scss.liquid

Remove a superfluous closing brace.
Adjust layout.

* Use `scssify` to remove nesting

Preliminary profiling indicates that using `scssify` on the small number of nested CSS rules produced by `activation.scss.liquid` is quick enough.

* Update head.scss

Manual attempt at prettier (pending installation in Atom).

* Avoid generation of nested CSS

Local profiling indicated that using `scssify` on each page takes about 1% of the build time.

- Update `_includes/css/activation.scss.liquid` to generate non-nested CSS.
- Remove use of `scssify` from `_includes/head.html`.

* Ignore false positives from validator

Ignores: `:1.810-1.823: error: CSS: Parse Error.` and `:1.811-1.824: error: CSS: Parse Error.`; had to shift things around since the local config overrides the CI flag.

* Inline `_sass/head.css`

* Update CHANGELOG.md

---------

Co-authored-by: Matthew Wang <matt@matthewwang.me>
This commit is contained in:
Peter Mosses 2023-10-01 14:47:26 +02:00 committed by GitHub
parent cd4f1b02b2
commit 2ccc451c2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 247 additions and 181 deletions

@ -84,8 +84,7 @@ jobs:
- name: Test with Nu Validator
uses: Cyb3r-Jak3/html5validator-action@2a593a9f2c10593cbac84791a6fc4c47e9a106c8
with:
root: _site
blacklist: line-numbers
config: fixtures/html5validator-config.yml
- name: Test with html-proofer
run: bundle exec htmlproofer _site --ignore-urls "/github.com/,/web.archive.org/"
env:

@ -20,8 +20,14 @@ Code changes to `main` that are *not* in the latest release:
### Bugfixes
- Fixed: remove href from the navigation link to the current page by [@pdmosses] in [#1356]
- Fixed: improve build time by [@pdmosses] in [#1358]
{: .warning }
[#1358] moved `_includes/nav.html` to the `_includes/components` directory,
Users who were overriding that file will need to adjust their sites accordingly.
[#1356]: https://github.com/just-the-docs/just-the-docs/pull/1356
[#1358]: https://github.com/just-the-docs/just-the-docs/pull/1358
## Release v0.6.2

@ -3,30 +3,38 @@
Depends on: page, site.
Results in: HTML for the breadcrumbs component.
Overwrites:
pages_list, parent_page, grandparent_page.
node, pages_list, parent_page, grandparent_page.
{%- endcomment -%}
{%- if page.url != "/" and page.parent -%}
{%- assign pages_list = site[page.collection]
| default: site.html_pages
| where_exp: "item", "item.title != nil"
| where_exp: "item", "item.has_children != nil" -%}
{%- assign pages_list = site[page.collection] | default: site.html_pages -%}
{%- if page.grand_parent -%}
{%- assign parent_page = pages_list
| where: "title", page.parent
| where: "parent", page.grand_parent
| first -%}
{%- assign grandparent_page = pages_list
| where: "title", page.grand_parent
| first -%}
{%- else -%}
{%- assign parent_page = pages_list
| where: "title", page.parent
| where_exp: "item", "item.parent == nil"
| first -%}
{%- endif -%}
{%- assign parent_page = nil -%}
{%- assign grandparent_page = nil -%}
{%- for node in pages_list -%}
{%- if node.has_children and page.grand_parent -%}
{%- if node.title == page.parent and node.parent == page.grand_parent -%}
{%- assign parent_page = node -%}
{%- endif -%}
{%- if node.title == page.grand_parent -%}
{%- assign grandparent_page = node -%}
{%- endif -%}
{%- if parent_page and grandparent_page -%}
{%- break -%}
{%- endif -%}
{%- elsif node.has_children and node.title == page.parent and node.parent == nil -%}
{%- assign parent_page = node -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}
<nav aria-label="Breadcrumb" class="breadcrumb-nav">
<ol class="breadcrumb-nav-list">

@ -1,5 +1,5 @@
{%- comment -%}
Include as: {%- include_cached nav.html pages=pages -%}
Include as: {%- include components/nav.html pages=pages -%}
Depends on: include.pages.
Results in: HTML for the navigation panel.
Includes:

@ -3,10 +3,9 @@
Depends on: page(?), site.
Results in: HTML for the side bar.
Includes:
title.html, nav.html, nav_footer_custom.html
title.html, components/site_nav.html, nav_footer_custom.html
Overwrites:
pages_top_size, collections_size, collection_entry,
collection_key, collection_value, collection, nav_footer_custom.
nav_footer_custom.
Should not be cached, because nav_footer_custom.html might depend on page.
{%- endcomment -%}
@ -17,59 +16,9 @@
<svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg>
</button>
</div>
<nav aria-label="Main" id="site-nav" class="site-nav">
{% assign pages_top_size = site.html_pages
| where_exp:"item", "item.title != nil"
| where_exp:"item", "item.parent == nil"
| where_exp:"item", "item.nav_exclude != true"
| size %}
{% if pages_top_size > 0 %}
{% include_cached nav.html pages=site.html_pages %}
{% endif %}
{%- if site.nav_external_links -%}
<ul class="nav-list">
{%- for node in site.nav_external_links -%}
<li class="nav-list-item external">
<a href="{{ node.url | absolute_url }}" class="nav-list-link external">
{{ node.title }}
{% unless node.hide_icon %}<svg viewBox="0 0 24 24" aria-labelledby="svg-external-link-title"><use xlink:href="#svg-external-link"></use></svg>{% endunless %}
</a>
</li>
{%- endfor -%}
</ul>
{%- endif -%}
{% if site.just_the_docs.collections %}
{% assign collections_size = site.just_the_docs.collections | size %}
{% for collection_entry in site.just_the_docs.collections %}
{% assign collection_key = collection_entry[0] %}
{% assign collection_value = collection_entry[1] %}
{% assign collection = site[collection_key] %}
{% if collection_value.nav_exclude != true %}
{% if collections_size > 1 or pages_top_size > 0 %}
{% if collection_value.nav_fold == true %}
<ul class="nav-list nav-category-list">
<li class="nav-list-item{% if page.collection == collection_key %} active{% endif %}">
{%- if collection.size > 0 -%}
<button class="nav-list-expander btn-reset" aria-label="Toggle collection {{ collection_value.name }}" aria-pressed="{% if page.collection == collection_key %}true{% else %}false{% endif %}">
<svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg>
</button>
{%- endif -%}
<div class="nav-category">{{ collection_value.name }}</div>
{% include_cached nav.html pages=collection %}
</li>
</ul>
{% else %}
<div class="nav-category">{{ collection_value.name }}</div>
{% include_cached nav.html pages=collection %}
{% endif %}
{% else %}
{% include_cached nav.html pages=collection %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
</nav>
{% include_cached components/site_nav.html %}
{% capture nav_footer_custom %}
{%- include nav_footer_custom.html -%}
{% endcapture %}

@ -0,0 +1,63 @@
{%- comment -%}
Include as: {%- include_cached components/site_nav.html -%}
Depends on: site.
Results in: HTML for the site-nav.
Includes:
components/nav.html
Overwrites:
pages_top_size, collections_size, collection_entry,
collection_key, collection_value, collection.
{%- endcomment -%}
<nav aria-label="Main" id="site-nav" class="site-nav">
{% assign pages_top_size = site.html_pages
| where_exp:"item", "item.title != nil"
| where_exp:"item", "item.parent == nil"
| where_exp:"item", "item.nav_exclude != true"
| size %}
{% if pages_top_size > 0 %}
{% include components/nav.html pages=site.html_pages %}
{% endif %}
{%- if site.nav_external_links -%}
<ul class="nav-list">
{%- for node in site.nav_external_links -%}
<li class="nav-list-item external">
<a href="{{ node.url | absolute_url }}" class="nav-list-link external">
{{ node.title }}
{% unless node.hide_icon %}<svg viewBox="0 0 24 24" aria-labelledby="svg-external-link-title"><use xlink:href="#svg-external-link"></use></svg>{% endunless %}
</a>
</li>
{%- endfor -%}
</ul>
{%- endif -%}
{% if site.just_the_docs.collections %}
{% assign collections_size = site.just_the_docs.collections | size %}
{% for collection_entry in site.just_the_docs.collections %}
{% assign collection_key = collection_entry[0] %}
{% assign collection_value = collection_entry[1] %}
{% assign collection = site[collection_key] %}
{% if collection_value.nav_exclude != true %}
{% if collections_size > 1 or pages_top_size > 0 %}
{% if collection_value.nav_fold == true %}
<ul class="nav-list nav-category-list">
<li class="nav-list-item">
{%- if collection.size > 0 -%}
<button class="nav-list-expander btn-reset" aria-label="Toggle collection {{ collection_value.name }}" aria-pressed="false">
<svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg>
</button>
{%- endif -%}
<div class="nav-category">{{ collection_value.name }}</div>
{% include components/nav.html pages=collection %}
</li>
</ul>
{% else %}
<div class="nav-category">{{ collection_value.name }}</div>
{% include components/nav.html pages=collection %}
{% endif %}
{% else %}
{% include components/nav.html pages=collection %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
</nav>

@ -1,7 +1,8 @@
{%- comment -%}
Include as: {%- include css/activation.scss.liquid -%}
Depends on: page, site.
Results in: page-dependent SCSS rules for inclusion in a head style element.
Results in: page-dependent (non-nested) CSS rules for inclusion in a head style element,
which needs to be suppressed when JS is enabled.
Includes:
sorted_pages.html.
Overwrites:
@ -11,7 +12,7 @@
activation_first_level_index, activation_second_level_index, activation_third_level_index.
Should not be cached, because it depends on page.
(For a site with only top-level pages, the rendering of this file is always empty.
This property could be detected, and might halve the build time for such sites.)
This property could be detected, and used to reduce the build time for such sites.)
{%- endcomment -%}
{%- unless page.title == nil or page.nav_exclude == true -%}
@ -27,6 +28,11 @@
{%- assign activation_first_level_reversed = nil -%}
{%- assign activation_second_level_reversed = nil -%}
{%- comment -%}
The generated CSS depends on the position of the current page in each level in
the navigation.
{%- endcomment -%}
{%- assign activation_title = page.grand_parent | default: page.parent | default: page.title -%}
{%- assign activation_first_level = activation_pages
| where_exp: "item", "item.parent == nil" -%}
@ -85,10 +91,18 @@
{%- unless activation_second_level_index == nil and activation_third_level_index -%}
{%- comment -%}
The generated CSS uses a prefix that depends on the number of ordinary pages
and on the page collections.
{%- endcomment -%}
{%- if page.collection == nil -%}
{%- capture activation_collection_prefix -%}
.site-nav > .nav-list:nth-child(1):not(.nav-category-list)
.site-nav > .nav-list:nth-child(1):not(.nav-category-list)
{%- endcapture -%}
{%- capture activation_other_collection_prefix -%}
.site-nav > .nav-list:not(:nth-child(1):not(.nav-category-list))
{%- endcapture -%}
{%- else -%}
@ -114,57 +128,92 @@
{%- capture activation_collection_prefix -%}
.site-nav > .nav-list:nth-of-type({{ activation_index }}){% if site.just_the_docs.collections[page.collection].nav_fold == true %} > .nav-list-item > .nav-list{% endif %}
{%- endcapture -%}
{%- capture activation_other_collection_prefix -%}
.site-nav > .nav-list:not(:nth-of-type({{ activation_index }}))
{%- endcapture -%}
{%- endif -%}
// Styling for the nav-list-link to the current page:
{{ activation_collection_prefix }} {
> .nav-list-item:not(.external):nth-child({{ activation_first_level_index }}){%- if activation_second_level_index %} > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }}){%- if activation_third_level_index %} > .nav-list > .nav-list-item:nth-child({{ activation_third_level_index }}){% endif %}{% endif %} {
> .nav-list-link {
display: block;
font-weight: 600;
text-decoration: none;
background-image: linear-gradient(
-90deg,
rgba($feedback-color, 1) 0%,
rgba($feedback-color, 0.8) 80%,
rgba($feedback-color, 0) 100%
);
}
}
{%- comment -%}
The required background image of the link to the current page may involve SCSS.
To avoid page-dependent SCSS, all nav links initially have that background image.
The following rule removes the image from the links to all parents, siblings,
and children of the current page.
{%- endcomment %}
{% if activation_third_level_index -%}
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list-link,
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list > .nav-list-item > .nav-list-link,
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list > .nav-list-item > .nav-list > .nav-list-item:not(:nth-child({{ activation_third_level_index }})) > .nav-list-link {
background-image: none;
}
// Styling for nav-list-expanders at first and second levels:
{{ activation_collection_prefix }} {
> .nav-list-item:nth-child({{ activation_first_level_index }}){%- if activation_second_level_index %},
> .nav-list-item:nth-child({{ activation_first_level_index }}) > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }}){% endif %} {
> .nav-list-expander svg {
@if $nav-list-expander-right {
transform: rotate(-90deg);
} @else {
transform: rotate(90deg);
}
}
{%- elsif activation_second_level_index -%}
> .nav-list {
display: block;
}
}
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list-link,
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list > .nav-list-item:not(:nth-child({{ activation_second_level_index }})) > .nav-list-link,
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list > .nav-list-item > .nav-list > .nav-list-item > .nav-list-link {
background-image: none;
}
// Styling for nav-list-expander for categories:
.site-nav > .nav-category-list > .nav-list-item {
> .nav-list-expander svg {
@if $nav-list-expander-right {
transform: rotate(-90deg);
} @else {
transform: rotate(90deg);
}
}
{%- else -%}
> .nav-list {
display: block;
}
{{ activation_collection_prefix }} > .nav-list-item:not(.external):not(:nth-child({{ activation_first_level_index }})) > .nav-list-link,
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list > .nav-list-item > .nav-list-link,
{{ activation_collection_prefix }} > .nav-list-item:not(.external) > .nav-list > .nav-list-item > .nav-list > .nav-list-item > .nav-list-link {
background-image: none;
}
{%- endif %}
{%- comment -%}
The following rule removes the image from the links to pages in other collections.
{%- endcomment %}
{{ activation_other_collection_prefix }} .nav-list-link,
.site-nav .nav-list-link.external {
background-image: none;
}
{%- comment -%}
The following rule styles the link to the current page.
{%- endcomment %}
{{ activation_collection_prefix }} > .nav-list-item:not(.external):nth-child({{ activation_first_level_index }})
{%- if activation_second_level_index %} > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }})
{%- if activation_third_level_index %} > .nav-list > .nav-list-item:nth-child({{ activation_third_level_index }})
{%- endif -%}
{%- endif %} > .nav-list-link {
font-weight: 600;
text-decoration: none;
}
{%- comment -%}
The following rules unfold all collections, and display the links to any children
of the current page.
To avoid dependence on the SCSS variable nav-list-expander-right, the direction
of the rotation of the expander icon is fixed, and corresponds to the appearance
when nav-list-expander-right is true. This results in a minor visual difference
between the appearance of active expander icons when JS is enabled/disabled and
nav-list-expander-right is false, which seems unavoidable.
{%- endcomment %}
.site-nav > .nav-category-list > .nav-list-item > .nav-list-expander svg,
{{ activation_collection_prefix }} > .nav-list-item:nth-child({{ activation_first_level_index }}) > .nav-list-expander svg
{%- if activation_second_level_index -%},
{{ activation_collection_prefix }} > .nav-list-item:nth-child({{ activation_first_level_index }}) > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }}) > .nav-list-expander svg
{%- endif %} {
transform: rotate(-90deg);
}
.site-nav > .nav-category-list > .nav-list-item > .nav-list,
{{ activation_collection_prefix }} > .nav-list-item:nth-child({{ activation_first_level_index }}) > .nav-list
{%- if activation_second_level_index %},
{{ activation_collection_prefix }} > .nav-list-item:nth-child({{ activation_first_level_index }}) > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }}) > .nav-list
{%- endif %} {
display: block;
}
{%- endunless -%}

@ -4,7 +4,7 @@
site.search_enabled, site.static_files, site.favicon_ico.
Results in: HTML for the head element.
Includes:
head_nav.html, head_custom.html.
css/activation.scss.liquid, head_custom.html.
Overwrites:
ga_tracking_ids, ga_property, file, favicon.
Should not be cached, because included files depend on page.
@ -16,7 +16,11 @@
<link rel="stylesheet" href="{{ '/assets/css/just-the-docs-default.css' | relative_url }}">
{% include head_nav.html %}
<link rel="stylesheet" href="{{ '/assets/css/just-the-docs-head-nav.css' | relative_url }}">
<style id="jtd-nav-activation">
{% include css/activation.scss.liquid %}
</style>
{% if site.ga_tracking != nil %}
{% assign ga_tracking_ids = site.ga_tracking | split: "," %}

@ -1,48 +0,0 @@
{%- comment -%}
Include as: {%- include head_nav.html -%}
Depends on: site.color_scheme.
Results in: HTML for a page-specific style element.
Includes:
css/activation.scss.liquid.
Overwrites:
activation, test_scss, scss, css, index, count.
Should not be cached, because css/activation.scss.liquid depends on page.
{%- endcomment -%}
{% capture activation %}
{% include css/activation.scss.liquid %}
{%- endcapture -%}
{% capture test_scss %}
@import "./support/support";
@import "./color_schemes/light";
{{ activation }}
{%- endcapture -%}
{%- capture scss -%}
@import "./support/support";
@import "./custom/setup";
{% if site.color_scheme and site.color_scheme != "nil" -%}
{%- assign color_scheme = site.color_scheme -%}
{%- else -%}
{%- assign color_scheme = "light" -%}
{%- endif %}
@import "./color_schemes/light";
{% unless color_scheme == "light" %}
@import "./color_schemes/{{ color_scheme }}";
{% endunless %}
{{ activation }}
{%- endcapture -%}
{%- comment -%}
Convert to CSS, then remove the color_scheme import rules to avoid duplication.
The value of count is page-dependent, but independent of custom color schemes.
{%- endcomment -%}
{%- assign count = test_scss | scssify | split: ".site-nav" | size -%}
{%- unless count == 1 %}
{%- assign index = 1 | minus: count -%}
{%- assign css = scss | scssify | split: ".site-nav" | slice: index, count | join: ".site-nav" -%}
<style type="text/css">
{{ css | prepend: ".site-nav" }}
</style>
{%- endunless %}

@ -0,0 +1,24 @@
---
---
{%- if site.color_scheme and site.color_scheme != "nil" -%}
{%- assign color_scheme = site.color_scheme -%}
{%- else -%}
{%- assign color_scheme = "light" -%}
{%- endif -%}
{%- capture newline %}
{% endcapture -%}
{%- capture scss -%}
{% include css/just-the-docs.scss.liquid color_scheme=color_scheme %}
.nav-list .nav-list-item .nav-list-link {
background-image: linear-gradient(
-90deg,
rgba($feedback-color, 1) 0%,
rgba($feedback-color, 0.8) 80%,
rgba($feedback-color, 0) 100%
);
}
{%- endcapture -%}
{{ scss | scssify | split: newline | slice: -3, 3 | join: newline }}

@ -39,7 +39,7 @@ function initNav() {
const mainHeader = document.getElementById('main-header');
const menuButton = document.getElementById('menu-button');
disableHeadStyleSheet();
disableHeadStyleSheets();
jtd.addEvent(menuButton, 'click', function(e){
e.preventDefault();
@ -68,13 +68,19 @@ function initNav() {
{%- endif %}
}
// The page-specific <style> in the <head> is needed only when JS is disabled.
// Moreover, it incorrectly overrides dynamic stylesheets set by setTheme(theme).
// The page-specific stylesheet is assumed to have index 1 in the list of stylesheets.
// The <head> element is assumed to include the following stylesheets:
// 0. a <link> to /assets/css/just-the-docs-default.css
// 1. a <link> to /assets/css/just-the-docs-head-nav.css
// 2. a <style> containing the result of _includes/css/activation.scss.liquid.
// It also includes any styles provided by users in _includes/head_custom.html.
// Stylesheet 2 may be missing (compression can remove empty <style> elements)
// so disableHeadStyleSheet() needs to access it by its id.
function disableHeadStyleSheet() {
if (document.styleSheets[1]) {
document.styleSheets[1].disabled = true;
function disableHeadStyleSheets() {
document.styleSheets[1].disabled = true;
const activation = document.getElementById('jtd-nav-activation');
if (activation) {
activation.disabled = true;
}
}

@ -0,0 +1,6 @@
root: _site
blacklist:
- "line-numbers"
ignore:
- "1.810-1.823: error: CSS: Parse Error."
- "1.811-1.824: error: CSS: Parse Error."