Skip to content

Commit 2eacfcc

Browse files
committed
Optimize lazy load navigation
1 parent a261934 commit 2eacfcc

File tree

17 files changed

+126
-36
lines changed

17 files changed

+126
-36
lines changed

src/Elastic.ApiExplorer/ApiViewModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public GlobalLayoutViewModel CreateGlobalLayoutModel() =>
3737
Previous = null,
3838
Next = null,
3939
NavigationHtml = NavigationHtml,
40+
NavigationFileName = string.Empty,
4041
UrlPathPrefix = BuildContext.UrlPathPrefix,
4142
AllowIndexing = BuildContext.AllowIndexing,
4243
CanonicalBaseUrl = BuildContext.CanonicalBaseUrl,

src/Elastic.ApiExplorer/OpenApiGenerator.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,12 @@ private async Task<IFileInfo> Render<T>(INavigationItem current, T page, ApiRend
292292
renderContext = renderContext with
293293
{
294294
CurrentNavigation = current,
295-
NavigationHtml = navigationHtml
295+
NavigationHtml = navigationHtml switch
296+
{
297+
EmptyNavigationRenderResult => string.Empty,
298+
OkNavigationRenderResult result => result.Html,
299+
_ => throw new Exception("Unexpected navigation render result")
300+
}
296301
};
297302
await using var stream = _writeFileSystem.FileStream.New(outputFile.FullName, FileMode.OpenOrCreate);
298303
await page.RenderAsync(stream, renderContext, ctx);

src/Elastic.Documentation.Site/Assets/main.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,24 @@ import { $, $$ } from 'select-dom'
1515
import { UAParser } from 'ua-parser-js'
1616

1717
const { getOS } = new UAParser()
18+
const isLazyLoadNavigationEnabled = $('meta[property="docs:feature:lazy-load-navigation"]')?.content === 'true';
1819

1920
document.addEventListener('htmx:load', function (event) {
20-
console.log('htmx:load')
21-
console.log(event.detail)
2221
initTocNav()
2322
initHighlight()
2423
initCopyButton()
2524
initTabs()
26-
initNav()
25+
26+
// We this so that the navigation is not initialized twice
27+
if (isLazyLoadNavigationEnabled) {
28+
if (event.detail.elt.id === 'nav-tree')
29+
{
30+
initNav()
31+
}
32+
} else
33+
{
34+
initNav()
35+
}
2736
initSmoothScroll()
2837
openDetailsWithAnchor()
2938
initDismissibleBanner()

src/Elastic.Documentation.Site/Layout/_Head.cshtml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@
3434
{
3535
<meta property="og:url" content="@Model.CanonicalUrl" />
3636
}
37+
<meta property="docs:feature:lazy-load-navigation" content="@Model.Features.LazyLoadNavigation" />

src/Elastic.Documentation.Site/Layout/_PagesNav.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
@if (Model.Features.LazyLoadNavigation)
55
{
6-
<div hx-get="@(Model.CurrentNavigationItem.Url + (Model.CurrentNavigationItem.Url.EndsWith('/') ? "index.nav.html" : "/index.nav.html"))" hx-trigger="load" hx-params="nav" hx-push-url="false" hx-swap="innerHTML" hx-target="#pages-nav"></div>
6+
<div hx-get="@(Model.UrlPathPrefix?.TrimEnd('/') + "/" + Model.NavigationFileName)" hx-trigger="load" hx-params="nav" hx-push-url="false" hx-swap="innerHTML" hx-target="#pages-nav"></div>
77
}
88
<nav
99
id="pages-nav"

src/Elastic.Documentation.Site/Navigation/INavigationHtmlWriter.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,30 @@ public interface INavigationHtmlWriter
1010
{
1111
const int AllLevels = -1;
1212

13-
Task<string> RenderNavigation(IRootNavigationItem<INavigationModel, INavigationItem> currentRootNavigation, Uri navigationSource, int maxLevel, Cancel ctx = default);
13+
Task<INavigationRenderResult> RenderNavigation(IRootNavigationItem<INavigationModel, INavigationItem> currentRootNavigation, Uri navigationSource,
14+
int maxLevel, Cancel ctx = default);
1415

1516
async Task<string> Render(NavigationViewModel model, Cancel ctx)
1617
{
1718
var slice = _TocTree.Create(model);
1819
return await slice.RenderAsync(cancellationToken: ctx);
1920
}
2021
}
22+
23+
public interface INavigationRenderResult
24+
{
25+
string Html { get; init; }
26+
string Id { get; init; }
27+
}
28+
29+
public record OkNavigationRenderResult : INavigationRenderResult
30+
{
31+
public required string Html { get; init; }
32+
public required string Id { get; init; }
33+
}
34+
35+
public record EmptyNavigationRenderResult : INavigationRenderResult
36+
{
37+
public string Html { get; init; } = string.Empty;
38+
public string Id { get; init; } = string.Empty;
39+
}

src/Elastic.Documentation.Site/Navigation/IsolatedBuildNavigationHtmlWriter.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System.Collections.Concurrent;
66
using Elastic.Documentation.Configuration;
7+
using Elastic.Documentation.Extensions;
78

89
namespace Elastic.Documentation.Site.Navigation;
910

@@ -12,19 +13,30 @@ public class IsolatedBuildNavigationHtmlWriter(BuildContext context, IRootNaviga
1213
{
1314
private readonly ConcurrentDictionary<(string, int), string> _renderedNavigationCache = [];
1415

15-
public async Task<string> RenderNavigation(IRootNavigationItem<INavigationModel, INavigationItem> currentRootNavigation, Uri navigationSource, int maxLevel, Cancel ctx = default)
16+
public async Task<INavigationRenderResult> RenderNavigation(IRootNavigationItem<INavigationModel, INavigationItem> currentRootNavigation,
17+
Uri navigationSource, int maxLevel, Cancel ctx = default)
1618
{
1719
var navigation = context.Configuration.Features.PrimaryNavEnabled || currentRootNavigation.IsUsingNavigationDropdown
1820
? currentRootNavigation
1921
: siteRoot;
2022

23+
var id = ShortId.Create($"{(navigation.Id, maxLevel).GetHashCode()}");
24+
2125
if (_renderedNavigationCache.TryGetValue((navigation.Id, maxLevel), out var value))
22-
return value;
26+
return new OkNavigationRenderResult
27+
{
28+
Html = value,
29+
Id = id
30+
};
2331

2432
var model = CreateNavigationModel(navigation, maxLevel);
2533
value = await ((INavigationHtmlWriter)this).Render(model, ctx);
2634
_renderedNavigationCache[(navigation.Id, maxLevel)] = value;
27-
return value;
35+
return new OkNavigationRenderResult
36+
{
37+
Html = value,
38+
Id = id
39+
};
2840
}
2941

3042
private NavigationViewModel CreateNavigationModel(IRootNavigationItem<INavigationModel, INavigationItem> navigation, int maxLevel) =>

src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@using Elastic.Documentation.Site.Navigation
22
@inherits RazorSlice<Elastic.Documentation.Site.Navigation.NavigationViewModel>
33

4-
<div class="pb-20 font-body">
4+
<div class="pb-20 font-body" id="nav-tree">
55
@{
66
var currentTopLevelItem = Model.TopLevelItems.FirstOrDefault(i => i.Id == Model.Tree.Id) ?? Model.Tree;
77
}

src/Elastic.Documentation.Site/_ViewModels.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public record GlobalLayoutViewModel
2727
public required INavigationItem? Next { get; init; }
2828

2929
public required string NavigationHtml { get; init; }
30+
public required string NavigationFileName { get; init; }
3031
public required string? UrlPathPrefix { get; init; }
3132
public required Uri? CanonicalBaseUrl { get; init; }
3233
public string? CanonicalUrl => CanonicalBaseUrl is not null ?

src/Elastic.Markdown/Exporters/DocumentationFileExporter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class DocumentationFileExporter(IFileSystem readFileSystem, IFileSystem w
6666
public override async ValueTask ProcessFile(ProcessingFileContext context, Cancel ctx)
6767
{
6868
if (context.File is MarkdownFile markdown)
69-
context.MarkdownDocument = await context.HtmlWriter.WriteAsync(context.OutputFile, markdown, context.ConversionCollector, ctx);
69+
context.MarkdownDocument = await context.HtmlWriter.WriteAsync(context.BuildContext.DocumentationOutputDirectory, context.OutputFile, markdown, context.ConversionCollector, ctx);
7070
else
7171
{
7272
if (context.OutputFile.Directory is { Exists: false })

0 commit comments

Comments
 (0)