lazyLoad (#13)

* lazy load posts
This commit is contained in:
Tommy Parnell
2021-10-18 21:48:08 -04:00
committed by GitHub
parent 27151adf65
commit f300df90c1
11 changed files with 82 additions and 47 deletions

View File

@@ -14,7 +14,7 @@ namespace TerribleDev.Blog.Web.Factories
public static PostCache ProjectPostCache(IEnumerable<IPost> rawPosts)
{
var orderedPosts = rawPosts.OrderByDescending(a => a.PublishDate);
var posts = new List<IPost>();
var posts = new List<IPost>(orderedPosts);
var urlToPosts = new Dictionary<string, IPost>();
var tagsToPost = new Dictionary<string, IList<IPost>>();
var postsByPage = new Dictionary<int, IList<IPost>>();

View File

@@ -17,25 +17,21 @@ namespace TerribleDev.Blog.Web
{
public class BlogFactory
{
public IEnumerable<IPost> GetAllPosts(string domain)
public async Task<IEnumerable<IPost>> GetAllPostsAsync(string domain)
{
// why didn't I use f# I'd have a pipe operator by now
var posts = GetPosts();
var list = new ConcurrentBag<IPost>();
Parallel.ForEach(posts, post =>
{
var (text, fileInfo) = GetFileText(post);
list.Add(ParsePost(text, fileInfo.Name, domain));
});
return list;
return await Task.WhenAll(posts.Select(async (post) => {
var (text, fileInfo) = await GetFileText(post);
return ParsePost(text, fileInfo.Name, domain);
}));
}
private static (string text, FileInfo fileInfo) GetFileText(string filePath)
private static async Task<(string text, FileInfo fileInfo)> GetFileText(string filePath)
{
var fileInfo = new FileInfo(filePath);
var text = File.ReadAllText(fileInfo.FullName);
var text = await File.ReadAllTextAsync(fileInfo.FullName);
return (text, fileInfo);
}
public IEnumerable<string> GetPosts() => Directory.EnumerateFiles(Path.Combine(Directory.GetCurrentDirectory(), "Posts"), "*.md", SearchOption.TopDirectoryOnly);
@@ -46,13 +42,7 @@ namespace TerribleDev.Blog.Web
return serializer.Deserialize<PostSettings>(ymlText);
}
public IPost ParsePost(string postText, string fileName, string domain)
{
var splitFile = postText.Split("---");
var ymlRaw = splitFile[0];
var markdownText = string.Join("", splitFile.Skip(1));
var postSettings = ParseYaml(ymlRaw);
var resolvedUrl = !string.IsNullOrWhiteSpace(postSettings.permalink) ? postSettings.permalink : fileName.Split('.')[0].Replace(' ', '-').WithoutSpecialCharacters();
public (string postContent, string postContentPlain, string summary, string postSummaryPlain, IList<string> postImages) ResolveContentForPost(string markdownText, string fileName, string resolvedUrl, string domain) {
List<string> postImages = new List<string>();
var pipeline = new MarkdownPipelineBuilder()
.Use(new AbsoluteLinkConverter(resolvedUrl, domain))
@@ -67,6 +57,15 @@ namespace TerribleDev.Blog.Web
var summary = postContent.Split("<!-- more -->")[0];
var postSummaryPlain = postContentPlain.Split("<!-- more -->")[0];
return (postContent, postContentPlain, summary, postSummaryPlain, postImages);
}
public IPost ParsePost(string postText, string fileName, string domain)
{
var splitFile = postText.Split("---");
var ymlRaw = splitFile[0];
var markdownText = string.Join("", splitFile.Skip(1));
var postSettings = ParseYaml(ymlRaw);
var resolvedUrl = !string.IsNullOrWhiteSpace(postSettings.permalink) ? postSettings.permalink : fileName.Split('.')[0].Replace(' ', '-').WithoutSpecialCharacters();
return new Post()
{
@@ -76,12 +75,17 @@ namespace TerribleDev.Blog.Web
RelativeUrl = $"/{resolvedUrl}/",
CanonicalUrl = $"https://blog.terrible.dev/{resolvedUrl}/",
UrlWithoutPath = resolvedUrl,
Content = new HtmlString(postContent),
Summary = new HtmlString(summary),
SummaryPlain = postSummaryPlain,
SummaryPlainShort = (postContentPlain.Length <= 147 ? postContentPlain : postContentPlain.Substring(0, 146)) + "...",
ContentPlain = postContentPlain,
Images = postImages.Distinct().ToList()
Content = new Lazy<IPostContent>(() => {
(string postContent, string postContentPlain, string summary, string postSummaryPlain, IList<string> postImages) = ResolveContentForPost(markdownText, fileName, resolvedUrl, domain);
return new PostContent() {
Content = new HtmlString(postContent),
Images = postImages,
ContentPlain = postContent,
Summary = new HtmlString(summary),
SummaryPlain = postSummaryPlain,
SummaryPlainShort = (postContentPlain.Length <= 147 ? postContentPlain : postContentPlain.Substring(0, 146)) + "..."
};
}),
};
}
}

View File

@@ -13,14 +13,9 @@ namespace TerribleDev.Blog.Web.Models
string UrlWithoutPath { get; set; }
string RelativeUrl { get; set; }
string Title { get; set; }
HtmlString Summary { get; set; }
DateTime PublishDate { get; set; }
HtmlString Content { get; set; }
string ContentPlain { get; set; }
string SummaryPlain { get; set; }
string SummaryPlainShort { get; set; }
IList<string> tags { get; set; }
IList<string> Images { get; set;}
Lazy<IPostContent> Content { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Html;
namespace TerribleDev.Blog.Web.Models
{
public interface IPostContent
{
HtmlString Content { get; set; }
HtmlString Summary { get; set; }
string ContentPlain { get; set; }
string SummaryPlain { get; set; }
string SummaryPlainShort { get; set; }
IList<string> Images { get; set; }
}
}

View File

@@ -14,12 +14,7 @@ namespace TerribleDev.Blog.Web.Models
public string RelativeUrl { get; set; }
public string Title { get; set; }
public DateTime PublishDate { get; set; }
public HtmlString Content { get; set; }
public HtmlString Summary { get; set; }
public string ContentPlain { get; set; }
public string SummaryPlain { get; set; }
public string SummaryPlainShort { get; set; }
public IList<string> tags { get; set; }
public IList<string> Images { get; set; }
public Lazy<IPostContent> Content { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Html;
namespace TerribleDev.Blog.Web.Models
{
public class PostContent : IPostContent
{
public HtmlString Content { get; set; }
public HtmlString Summary { get; set; }
public string ContentPlain { get; set; }
public string SummaryPlain { get; set; }
public string SummaryPlainShort { get; set; }
public IList<string> Images { get; set; }
}
}

View File

@@ -39,8 +39,16 @@ namespace TerribleDev.Blog.Web
services.AddSingleton(getBlog());
}
services.AddSingleton((i) => {
var posts = new BlogFactory().GetAllPosts(Env.IsDevelopment() ? "https://localhost:5001": "https://blog.terrible.dev");
return BlogCacheFactory.ProjectPostCache(posts);
var posts = new BlogFactory().GetAllPostsAsync(Env.IsDevelopment() ? "https://localhost:5001": "https://blog.terrible.dev").Result;
var postCache = BlogCacheFactory.ProjectPostCache(posts);
if(Env.IsProduction()) {
foreach(var post in postCache.PostsAsLists)
{
// if we are in production turn off lazy loading
var value = post.Content.Value;
}
}
return postCache;
});
services.AddApplicationInsightsTelemetry();
var controllerBuilder = services.AddControllersWithViews();

View File

@@ -9,26 +9,26 @@
</cache>
@section Head {
<meta name="description" content="@Model.SummaryPlainShort" />
<meta name="description" content="@Model.Content.Value.SummaryPlainShort" />
<meta property="og:type" content="blog">
<meta property="og:title" content="@Model.Title">
<meta property="og:url" content="@Model.CanonicalUrl">
<meta property="og:site_name" content="@config.Title">
<meta property="og:description" content="@Model.SummaryPlainShort">
<meta property="og:description" content="@Model.Content.Value.SummaryPlainShort">
<meta property="og:updated_time" content="@Model.PublishDate.ToString("O")">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="@Model.Title">
<meta name="twitter:description" content="@Model.SummaryPlainShort">
<meta name="twitter:description" content="@Model.Content.Value.SummaryPlainShort">
<meta name="twitter:site" content="@@TerribleDev">
<meta name="twitter:creator" content="@@TerribleDev">
<link rel="canonical" href="@Model.CanonicalUrl" />
@foreach(var image in Model.Images.Take(6))
@foreach(var image in Model.Content.Value.Images.Take(6))
{
<meta property="og:image" content="@image">
}
@if(Model.Images.Count > 0)
@if(Model.Content.Value.Images.Count > 0)
{
<meta name="twitter:image" content="@(Model.Images[0])">
<meta name="twitter:image" content="@(Model.Content.Value.Images[0])">
}
<meta property="og:image" content="https://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061?s=640" />
}

View File

@@ -3,7 +3,7 @@
<article itemprop="blogPost">
<h1 itemprop="headline" class="headline">@Model.Title</h1>
<time class="headlineSubtext" itemprop="datePublished" content="@Model.PublishDate.ToString()">@Model.PublishDate.ToString("D")</time>
@Model.Content
@Model.Content.Value.Content
@if (Model.tags.Count > 0)
{
<div>

View File

@@ -4,7 +4,7 @@
<h3 itemprop="headline" class="headline"><a href="@Model.RelativeUrl" class="link-unstyled">@Model.Title</a></h3>
<time class="headlineSubtext" itemprop="datePublished" content="@Model.PublishDate.ToString()">@Model.PublishDate.ToString("D")</time>
<div itemprop="articleBody">
@Model.Summary
@Model.Content.Value.Summary
</div>
<a href="@Model.RelativeUrl">Continue Reading </a>
</article>