Compare commits
14 Commits
feat-highl
...
2b9c374e8c
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b9c374e8c | |||
| 4df3b98e6d | |||
| c293d2f6d7 | |||
| 132261831b | |||
| 043376c6d3 | |||
| 4682dacc79 | |||
| 383dd41695 | |||
| 7f3221fde9 | |||
| 05ea729950 | |||
| dcad453eb1 | |||
| dec2bc937a | |||
| b9c44408ad | |||
| e1c5362cf5 | |||
| bdcfed5506 |
@@ -7,7 +7,7 @@ jobs:
|
|||||||
Build-Blog-Image:
|
Build-Blog-Image:
|
||||||
runs-on: archlinux
|
runs-on: archlinux
|
||||||
steps:
|
steps:
|
||||||
- uses: https://git.rrricardo.top/actions/checkout@v4
|
- uses: https://mirrors.rrricardo.top/actions/checkout.git@v4
|
||||||
name: Check out code
|
name: Check out code
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
@@ -18,12 +18,16 @@ jobs:
|
|||||||
- name: Build docker image
|
- name: Build docker image
|
||||||
run: |
|
run: |
|
||||||
cd YaeBlog
|
cd YaeBlog
|
||||||
docker build . -t registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
podman build . -t registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
||||||
|
- name: Workaround to make sure podman login succeed
|
||||||
|
run: |
|
||||||
|
mkdir /root/.docker
|
||||||
- name: Login aliyun docker registry
|
- name: Login aliyun docker registry
|
||||||
uses: https://git.rrricardo.top/actions/login-action@v3
|
uses: https://mirrors.rrricardo.top/actions/podman-login.git@v1
|
||||||
with:
|
with:
|
||||||
registry: registry.cn-beijing.aliyuncs.com
|
registry: registry.cn-beijing.aliyuncs.com
|
||||||
username: 初冬的朝阳
|
username: 初冬的朝阳
|
||||||
password: ${{ secrets.ALIYUN_PASSWORD }}
|
password: ${{ secrets.ALIYUN_PASSWORD }}
|
||||||
|
auth_file_path: /etc/containers/auth.json
|
||||||
- name: Push docker image
|
- name: Push docker image
|
||||||
run: docker push registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
run: podman push registry.cn-beijing.aliyuncs.com/jackfiled/blog:latest
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -484,4 +484,4 @@ $RECYCLE.BIN/
|
|||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
# Tailwind auto-generated stylesheet
|
# Tailwind auto-generated stylesheet
|
||||||
output.css
|
*.g.css
|
||||||
|
|||||||
41
YaeBlog.sln
41
YaeBlog.sln
@@ -1,41 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.0.31903.59
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YaeBlog", "YaeBlog\YaeBlog.csproj", "{20438EFD-8DDE-43AF-92E2-76495C29233C}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".gitea", ".gitea", "{9B5AAA29-37D8-454A-8D8F-3E6B6BCF38E6}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ADBC3DA8-F65C-4B5D-A97A-DC351F8E6592}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.gitea\workflows\build.yaml = .gitea\workflows\build.yaml
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{753B998C-1B9E-498F-B949-845CE86C4075}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
.gitattributes = .gitattributes
|
|
||||||
.gitignore = .gitignore
|
|
||||||
README.md = README.md
|
|
||||||
LICENSE = LICENSE
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{20438EFD-8DDE-43AF-92E2-76495C29233C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{20438EFD-8DDE-43AF-92E2-76495C29233C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{20438EFD-8DDE-43AF-92E2-76495C29233C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{20438EFD-8DDE-43AF-92E2-76495C29233C}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{ADBC3DA8-F65C-4B5D-A97A-DC351F8E6592} = {9B5AAA29-37D8-454A-8D8F-3E6B6BCF38E6}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
14
YaeBlog.slnx
Normal file
14
YaeBlog.slnx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Solution>
|
||||||
|
<Folder Name="/.gitea/" />
|
||||||
|
<Folder Name="/.gitea/workflows/">
|
||||||
|
<File Path=".gitea/workflows/build.yaml" />
|
||||||
|
</Folder>
|
||||||
|
<Folder Name="/Solution Items/">
|
||||||
|
<File Path=".editorconfig" />
|
||||||
|
<File Path=".gitattributes" />
|
||||||
|
<File Path=".gitignore" />
|
||||||
|
<File Path="LICENSE" />
|
||||||
|
<File Path="README.md" />
|
||||||
|
</Folder>
|
||||||
|
<Project Path="YaeBlog/YaeBlog.csproj" />
|
||||||
|
</Solution>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<link rel="stylesheet" href="YaeBlog.styles.css"/>
|
<link rel="stylesheet" href="YaeBlog.styles.css"/>
|
||||||
<link rel="icon" href="images/favicon.ico"/>
|
<link rel="icon" href="images/favicon.ico"/>
|
||||||
<link rel="stylesheet" href="globals.css"/>
|
<link rel="stylesheet" href="globals.css"/>
|
||||||
<link rel="stylesheet" href="output.css"/>
|
<link rel="stylesheet" href="tailwind.g.css"/>
|
||||||
<HeadOutlet/>
|
<HeadOutlet/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
18
YaeBlog/Extensions/AngleSharpExtensions.cs
Normal file
18
YaeBlog/Extensions/AngleSharpExtensions.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using AngleSharp.Dom;
|
||||||
|
|
||||||
|
namespace YaeBlog.Extensions;
|
||||||
|
|
||||||
|
public static class AngleSharpExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<IElement> EnumerateParentElements(this IElement element)
|
||||||
|
{
|
||||||
|
IElement? e = element.ParentElement;
|
||||||
|
|
||||||
|
while (e is not null)
|
||||||
|
{
|
||||||
|
IElement c = e;
|
||||||
|
e = e.ParentElement;
|
||||||
|
yield return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using YaeBlog.Abstraction;
|
using YaeBlog.Abstraction;
|
||||||
|
using YaeBlog.Extensions;
|
||||||
using YaeBlog.Models;
|
using YaeBlog.Models;
|
||||||
|
|
||||||
namespace YaeBlog.Processors;
|
namespace YaeBlog.Processors;
|
||||||
@@ -20,20 +21,21 @@ public sealed class EssayStylesPostRenderProcessor : IPostRenderProcessor
|
|||||||
|
|
||||||
ApplyGlobalCssStyles(document);
|
ApplyGlobalCssStyles(document);
|
||||||
BeatifyTable(document);
|
BeatifyTable(document);
|
||||||
|
BeatifyList(document);
|
||||||
|
BeatifyInlineCode(document);
|
||||||
|
|
||||||
return essay.WithNewHtmlContent(document.DocumentElement.OuterHtml);
|
return essay.WithNewHtmlContent(document.DocumentElement.OuterHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<string, string> _globalCssStyles = new()
|
private readonly Dictionary<string, string> _globalCssStyles = new()
|
||||||
{
|
{
|
||||||
{ "pre", "p-4 bg-slate-300 rounded-sm overflow-x-auto" },
|
{ "pre", "p-4 bg-gray-100 rounded-sm overflow-x-auto" },
|
||||||
{ "h2", "text-3xl font-bold py-4" },
|
{ "h2", "text-3xl font-bold py-4" },
|
||||||
{ "h3", "text-2xl font-bold py-3" },
|
{ "h3", "text-2xl font-bold py-3" },
|
||||||
{ "h4", "text-xl font-bold py-2" },
|
{ "h4", "text-xl font-bold py-2" },
|
||||||
{ "h5", "text-lg font-bold py-1" },
|
{ "h5", "text-lg font-bold py-1" },
|
||||||
{ "p", "p-2" },
|
{ "p", "p-2" },
|
||||||
{ "img", "w-11/12 block mx-auto my-2 rounded-md shadow-md" },
|
{ "img", "w-11/12 block mx-auto my-2 rounded-md shadow-md" },
|
||||||
{ "ul", "list-disc pl-2" }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private void ApplyGlobalCssStyles(IDocument document)
|
private void ApplyGlobalCssStyles(IDocument document)
|
||||||
@@ -99,4 +101,45 @@ public sealed class EssayStylesPostRenderProcessor : IPostRenderProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void BeatifyList(IDocument document)
|
||||||
|
{
|
||||||
|
foreach (IElement ulElement in from e in document.All
|
||||||
|
where e.LocalName == "ul"
|
||||||
|
select e)
|
||||||
|
{
|
||||||
|
// 首先给<ul>元素添加样式
|
||||||
|
ulElement.ClassList.Add("list-disc ml-10");
|
||||||
|
|
||||||
|
|
||||||
|
foreach (IElement liElement in from e in ulElement.Children
|
||||||
|
where e.LocalName == "li"
|
||||||
|
select e)
|
||||||
|
{
|
||||||
|
// 修改<li>元素中的<p>元素样式
|
||||||
|
// 默认的p-2间距有点太宽了
|
||||||
|
foreach (IElement pElement in from e in liElement.Children
|
||||||
|
where e.LocalName == "p"
|
||||||
|
select e)
|
||||||
|
{
|
||||||
|
pElement.ClassList.Remove("p-2");
|
||||||
|
pElement.ClassList.Add("p-1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BeatifyInlineCode(IDocument document)
|
||||||
|
{
|
||||||
|
// 选择不在<pre>元素内的<code>元素
|
||||||
|
// 即行内代码
|
||||||
|
IEnumerable<IElement> inlineCodes = from e in document.All
|
||||||
|
where e.LocalName == "code" && e.EnumerateParentElements().All(p => p.LocalName != "pre")
|
||||||
|
select e;
|
||||||
|
|
||||||
|
foreach (IElement e in inlineCodes)
|
||||||
|
{
|
||||||
|
e.ClassList.Add("bg-gray-100 inline p-1 rounded-xs");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ using YaeBlog.Models;
|
|||||||
|
|
||||||
namespace YaeBlog.Processors;
|
namespace YaeBlog.Processors;
|
||||||
|
|
||||||
public class ImagePostRenderProcessor(ILogger<ImagePostRenderProcessor> logger,
|
public class ImagePostRenderProcessor(
|
||||||
|
ILogger<ImagePostRenderProcessor> logger,
|
||||||
IOptions<BlogOptions> options)
|
IOptions<BlogOptions> options)
|
||||||
: IPostRenderProcessor
|
: IPostRenderProcessor
|
||||||
{
|
{
|
||||||
@@ -29,22 +30,27 @@ public class ImagePostRenderProcessor(ILogger<ImagePostRenderProcessor> logger,
|
|||||||
if (attr is not null)
|
if (attr is not null)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Found image link: '{}'", attr.Value);
|
logger.LogDebug("Found image link: '{}'", attr.Value);
|
||||||
attr.Value = GenerateImageLink(attr.Value, essay.FileName);
|
attr.Value = GenerateImageLink(attr.Value, essay.FileName, essay.IsDraft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return essay.WithNewHtmlContent(html.DocumentElement.OuterHtml);
|
return essay.WithNewHtmlContent(html.DocumentElement.OuterHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => nameof(ImagePostRenderProcessor);
|
public string Name => nameof(ImagePostRenderProcessor);
|
||||||
|
|
||||||
private string GenerateImageLink(string filename, string essayFilename)
|
private string GenerateImageLink(string filename, string essayFilename, bool isDraft)
|
||||||
{
|
{
|
||||||
|
// 如果图片路径中没有包含文件名
|
||||||
|
// 则添加文件名
|
||||||
if (!filename.Contains(essayFilename))
|
if (!filename.Contains(essayFilename))
|
||||||
{
|
{
|
||||||
filename = Path.Combine(essayFilename, filename);
|
filename = Path.Combine(essayFilename, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = Path.Combine(_options.Root, "posts", filename);
|
filename = isDraft
|
||||||
|
? Path.Combine(_options.Root, "drafts", filename)
|
||||||
|
: Path.Combine(_options.Root, "posts", filename);
|
||||||
|
|
||||||
if (!Path.Exists(filename))
|
if (!Path.Exists(filename))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="EnsurePnpmInstalled" BeforeTargets="Build">
|
<Target Name="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
<Message Importance="low" Text="Ensure pnpm is installed..."/>
|
<Message Importance="low" Text="Ensure pnpm is installed..."/>
|
||||||
<Exec Command="pnpm --version" ContinueOnError="true">
|
<Exec Command="pnpm --version" ContinueOnError="true">
|
||||||
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
|
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
|
||||||
@@ -25,9 +25,13 @@
|
|||||||
<Exec Command="pnpm install"/>
|
<Exec Command="pnpm install"/>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="TailwindGenerate" AfterTargets="EnsurePnpmInstalled">
|
<Target Name="TailwindGenerate" AfterTargets="EnsurePnpmInstalled" BeforeTargets="BeforeBuild" Condition="'$(_IsPublishing)' == 'yes'">
|
||||||
<Message Importance="normal" Text="Generate css files using tailwind..."/>
|
<Message Importance="normal" Text="Generate css files using tailwind..."/>
|
||||||
<Exec Command="pnpm tailwind -i wwwroot/input.css -o wwwroot/output.css"/>
|
<Exec Command="pnpm tailwindcss -i wwwroot/tailwind.css -o $(IntermediateOutputPath)tailwind.g.css"/>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="$(IntermediateOutputPath)tailwind.g.css" Visible="false" TargetPath="wwwroot/tailwind.g.css"/>
|
||||||
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "YaeBlog",
|
"name": "yae-blog",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {},
|
"scripts": {
|
||||||
|
"dev": "tailwindcss -i wwwroot/tailwind.css -o wwwroot/tailwind.g.css -w"
|
||||||
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tailwindcss": "^3.4.16"
|
"tailwindcss": "^4.0.0",
|
||||||
|
"@tailwindcss/cli": "^4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1121
YaeBlog/pnpm-lock.yaml
generated
1121
YaeBlog/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,8 @@
|
|||||||
title: 2021年终总结
|
title: 2021年终总结
|
||||||
date: 2022-01-12 16:27:19
|
date: 2022-01-12 16:27:19
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
|
- 年终总结
|
||||||
---
|
---
|
||||||
|
|
||||||
2021年已经过去,2022年已经来临。每每一年开始的时候,我都会展开一张纸或者新建一个文档,思量着又是一年时光,也该同诸大杂志一般,写几句意味深长的话语,怀念过去的时光,也祝福未来的自己。可往往脑海中已是三万字的长篇,落在笔头却又是一个字都没有了。
|
2021年已经过去,2022年已经来临。每每一年开始的时候,我都会展开一张纸或者新建一个文档,思量着又是一年时光,也该同诸大杂志一般,写几句意味深长的话语,怀念过去的时光,也祝福未来的自己。可往往脑海中已是三万字的长篇,落在笔头却又是一个字都没有了。
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: 2022年终总结
|
title: 2022年终总结
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
|
- 年终总结
|
||||||
date: 2022-12-30 14:58:12
|
date: 2022-12-30 14:58:12
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: 2022年暑假碎碎念
|
title: 2022年暑假碎碎念
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
typora-root-url: 2022-summer-vacation
|
typora-root-url: 2022-summer-vacation
|
||||||
date: 2022-08-22 15:39:13
|
date: 2022-08-22 15:39:13
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: 2023年年终总结
|
title: 2023年年终总结
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
|
- 年终总结
|
||||||
date: 2024-2-29 20:18:19
|
date: 2024-2-29 20:18:19
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: 人生代码大作业初体验
|
title: 人生代码大作业初体验
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
typora-root-url: big-homework
|
typora-root-url: big-homework
|
||||||
date: 2022-07-27 11:34:49
|
date: 2022-07-27 11:34:49
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: 日用Linux挑战 第0篇 初见Arch Linux
|
title: 日用Linux挑战 第0篇 初见Arch Linux
|
||||||
tags:
|
tags:
|
||||||
- Linux
|
- Linux
|
||||||
- 随笔
|
- 杂谈
|
||||||
date: 2023-01-15 22:23:08
|
date: 2023-01-15 22:23:08
|
||||||
typora-root-url: daily-linux-0
|
typora-root-url: daily-linux-0
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: 日用Linux挑战 第1篇 问题与挑战
|
title: 日用Linux挑战 第1篇 问题与挑战
|
||||||
tags:
|
tags:
|
||||||
- Linux
|
- Linux
|
||||||
- 随笔
|
- 杂谈
|
||||||
date: 2023-03-08 22:37:29
|
date: 2023-03-08 22:37:29
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: 日用Linux挑战 第2篇 Wayland
|
title: 日用Linux挑战 第2篇 Wayland
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
- Linux
|
- Linux
|
||||||
date: 2023-07-23 11:44:34
|
date: 2023-07-23 11:44:34
|
||||||
typora-root-url: daily-linux-2
|
typora-root-url: daily-linux-2
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: 日用Linux挑战 第3篇 放弃Wayland
|
title: 日用Linux挑战 第3篇 放弃Wayland
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
- Linux
|
- Linux
|
||||||
typora-root-url: daily-linux-3
|
typora-root-url: daily-linux-3
|
||||||
date: 2023-09-04 14:47:46
|
date: 2023-09-04 14:47:46
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: 日用Linux挑战 第4篇 新的开始
|
title: 日用Linux挑战 第4篇 新的开始
|
||||||
tags:
|
tags:
|
||||||
- Linux
|
- Linux
|
||||||
- 随笔
|
- 杂谈
|
||||||
date: 2024/03/09 14:00:00
|
date: 2024/03/09 14:00:00
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
100
YaeBlog/source/posts/hpc-2025-cpu-architecture.md
Normal file
100
YaeBlog/source/posts/hpc-2025-cpu-architecture.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
title: High Performance Computing 25 SP CPU Architecture
|
||||||
|
date: 2025-03-13T23:59:08.8167680+08:00
|
||||||
|
tags:
|
||||||
|
- 学习资料
|
||||||
|
- 高性能计算
|
||||||
|
---
|
||||||
|
|
||||||
|
How to use the newly available transistors?
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
Parallelsim:
|
||||||
|
|
||||||
|
Instruction Level Parallelism(ILP):
|
||||||
|
|
||||||
|
- **Implicit/transparent** to users/programmers.
|
||||||
|
- Instruction pipelining.
|
||||||
|
- Superscalar execution.
|
||||||
|
- Out of order execution.
|
||||||
|
- Register renaming.
|
||||||
|
- Speculative execution.
|
||||||
|
- Branch prediction.
|
||||||
|
|
||||||
|
Task Level Parallelism(TLP):
|
||||||
|
|
||||||
|
- **Explicit** to users/programmers.
|
||||||
|
- Multiple threads or processes executed simultaneously.
|
||||||
|
- Multi-core processors.
|
||||||
|
|
||||||
|
Data Parallelism:
|
||||||
|
|
||||||
|
- Vector processors and SIMD.
|
||||||
|
|
||||||
|
Von Neumann Architecture: the **stored-program** concept. Three components: processor, memory and data path.
|
||||||
|
|
||||||
|
Bandwidth: the gravity of modern computer system.
|
||||||
|
|
||||||
|
## Instruction Pipelining
|
||||||
|
|
||||||
|
Divide incoming instructions into a series of sequential steps performed by different processor unit to keep every part of the processor busy.
|
||||||
|
|
||||||
|
Superscalar execution can execute more than one instruction during a clock cycle.
|
||||||
|
|
||||||
|
Order of order execution.
|
||||||
|
|
||||||
|
Very long instruction word(VLIW): allows programs to explicitly specify instructions to execute at the same time.
|
||||||
|
|
||||||
|
EPIC: Explicit parallel instruction computing.
|
||||||
|
|
||||||
|
Move the complexity of instruction scheduling from the CPU hardware to the software compiler:
|
||||||
|
|
||||||
|
- Check dependencies between instructions.
|
||||||
|
- Assign instructions to the functional units.
|
||||||
|
- Determine when instructions are initiated placed together into a single word.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Comparisons between different architecture:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Multi-Core Processor Gala
|
||||||
|
|
||||||
|
Symmetric multiprocessing(SMP): a multiprocessor computer hardware and software architecture.
|
||||||
|
|
||||||
|
Two or more identical processors are connected to a **single shared main memory** and have full access to all input and output devices.
|
||||||
|
|
||||||
|
> Current trend: computer clusters, SMP computers connected with network.
|
||||||
|
|
||||||
|
Multithreading: exploiting thread-level parallelism.
|
||||||
|
|
||||||
|
Multithreading allows multiple threads to share the functional units of a single processor in an overlapping fashion **duplicating only private state**. A thread switch should be much more efficient than a process switch.
|
||||||
|
|
||||||
|
Hardware approaches to multithreading:
|
||||||
|
|
||||||
|
**fine-grained multithreading**:
|
||||||
|
|
||||||
|
- Switches between threads on each clock.
|
||||||
|
- Hide the throughput losses that arise from the both short and long stalls.
|
||||||
|
- Disadvantages: slow down the execution of an individual thread.
|
||||||
|
|
||||||
|
**Coarse-grained multithreading**:
|
||||||
|
|
||||||
|
- Switch threads only on costly stalls.
|
||||||
|
- Limited in its ability to overcome throughput losses
|
||||||
|
|
||||||
|
**Simultaneous multithreading(SMT)**:
|
||||||
|
|
||||||
|
- A variation on fine-grained multithreading
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Data Parallelism: Vector Processors
|
||||||
|
|
||||||
|
Provides high-level operations that work on vectors.
|
||||||
|
|
||||||
|
Length of the array also varies depending on hardware.
|
||||||
|
|
||||||
|
SIMD and its generalization in vector parallelism approach improved efficiency by the same operation be performed on multiple data elements.
|
||||||
BIN
YaeBlog/source/posts/hpc-2025-cpu-architecture/image-20250313184421305.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/hpc-2025-cpu-architecture/image-20250313184421305.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/hpc-2025-cpu-architecture/image-20250313184732892.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/hpc-2025-cpu-architecture/image-20250313184732892.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/hpc-2025-cpu-architecture/image-20250313190913475.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/hpc-2025-cpu-architecture/image-20250313190913475.png
(Stored with Git LFS)
Normal file
Binary file not shown.
33
YaeBlog/source/posts/hpc-2025-intro.md
Normal file
33
YaeBlog/source/posts/hpc-2025-intro.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
title: High Performance Computing 25 SP Introduction
|
||||||
|
date: 2025-03-08T00:31:54.5775860+08:00
|
||||||
|
tags:
|
||||||
|
- 高性能计算
|
||||||
|
- 学习资料
|
||||||
|
---
|
||||||
|
|
||||||
|
High performance computing is the use of supercomputing and computing clusters to solve advanced problems.
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
> High Performance Computing: Software execution speedup.
|
||||||
|
>
|
||||||
|
> High Throughput Computing: Resource utilization efficiency.
|
||||||
|
|
||||||
|
High performance computing:
|
||||||
|
|
||||||
|
- Provide computer power.
|
||||||
|
- Full-Domain HPC = Full-Stack HPC + Full-Network HPC.
|
||||||
|
|
||||||
|
Two key weapons: **partitioning** and **duplicating** to increase granularity.
|
||||||
|
|
||||||
|
HPC History:
|
||||||
|
|
||||||
|
- Mainframe computer
|
||||||
|
- Mini computer
|
||||||
|
- Cluster
|
||||||
|
- Grids
|
||||||
|
- Clouds
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: 大学生用啥配置——计算机专业
|
title: 大学生用啥配置——计算机专业
|
||||||
tags:
|
tags:
|
||||||
- 随笔
|
- 杂谈
|
||||||
typora-root-url: laptop-for-computer
|
typora-root-url: laptop-for-computer
|
||||||
date: 2022-06-13 16:17:27
|
date: 2022-06-13 16:17:27
|
||||||
---
|
---
|
||||||
|
|||||||
163
YaeBlog/source/posts/mlir-standalone.md
Normal file
163
YaeBlog/source/posts/mlir-standalone.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
---
|
||||||
|
title: 构建运行基于MLIR的独立项目
|
||||||
|
date: 2025-03-19T20:57:31.1928528+08:00
|
||||||
|
tags:
|
||||||
|
- 技术笔记
|
||||||
|
- LLVM
|
||||||
|
---
|
||||||
|
|
||||||
|
MLIR是多层次中间表示形式(Multi-Level Intermediate Representation),是LLVM项目中提供的一项新编译器开发基础设施,使得编译器开发者能够在源代码和可执行代码之间定义多层IR来保留程序信息指导编译优化。本博客指导如何创建一个独立(out-of-tree)的MLIR项目。
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
## 编译LLVM和MLIR
|
||||||
|
|
||||||
|
考虑到大多数的Linux发行版在打包LLVM时不会编译MLIR,因此自行编译安装包括MLIR项目的LLVM就成为开发独立MLIR项目的前置条件。
|
||||||
|
|
||||||
|
首先在GitHub上下载LLVM的源代码包,我这里选择最新的稳定版本`20.1.0`。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.0/llvm-project-20.1.0.src.tar.xz
|
||||||
|
```
|
||||||
|
|
||||||
|
下载之后解压进入,准备进行构建。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
tar xvf llvm-project-20.1.0.src.tar.xz
|
||||||
|
cd llvm-project-20.1.0.src
|
||||||
|
```
|
||||||
|
|
||||||
|
创建`build`文件夹,使用下面的命令进行生成构建文件。在这里选择使用`Release`构建类型,安装的位置是`~/.local/share/llvm`文件夹,构建的项目包括`llvm`、`clang`和`mlir`三个项目,并指定使用系统上的`clang`和`clang++`编译器作为编译过程中使用的编译器。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="/home/ricardo/.local/share/llvm-20.1.0" -DLLVM_ENABLE_PROJECTS="llvm;clang;mlir" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_INSTALL_UTILS=true ../llvm
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
生成构建文件之后使用`ninja`进行构建。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ninja
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
构建在我的i5-13600K上大约需要20分钟。
|
||||||
|
|
||||||
|
构建完成之后进行安装。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ninja install
|
||||||
|
```
|
||||||
|
|
||||||
|
## 编译MLIR官方的独立项目
|
||||||
|
|
||||||
|
MLIR的官方提供了一个独立项目,项目文件夹在`mlir/examples/standalone`中,将这个文件夹中的内容复制到我们需要的地方,尝试使用上面构建的`mlir`进行构建。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cp -r ~/Downloads/llvm-project-20.1.0.src/mlir/examples/standalone mlir-standalone
|
||||||
|
cd mlir-standalone
|
||||||
|
```
|
||||||
|
|
||||||
|
### 不启用测试
|
||||||
|
|
||||||
|
编译过程中可能遇到的最大问题是`llvm-lit`,这个使用`python`编写的LLVM集成测试工具,在`standalone`的`README.md`中要求编译过程中使用`LLVM_EXTERNAL_LIT`变量指定到LLVM编译过程中生成的`llvm-lit`可执行文件。
|
||||||
|
|
||||||
|
> 也许就是因为`llvm-lit`是用Python撰写的,所以`llvm-lit`不会安装到`PREFIX`指定的位置。
|
||||||
|
|
||||||
|
不过我们可以禁用测试(笑)。在`CMakeLists.txt`文件中注释对于测试文件夹的添加:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
add_subdirectory(include)
|
||||||
|
add_subdirectory(lib)
|
||||||
|
if(MLIR_ENABLE_BINDINGS_PYTHON)
|
||||||
|
message(STATUS "Enabling Python API")
|
||||||
|
add_subdirectory(python)
|
||||||
|
endif()
|
||||||
|
#add_subdirectory(test)
|
||||||
|
add_subdirectory(standalone-opt)
|
||||||
|
add_subdirectory(standalone-plugin)
|
||||||
|
add_subdirectory(standalone-translate)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
回到构建文件夹,使用如下的`cmake`指令生成构建文件。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
export LLVM_DIR=/home/ricardo/.local/share/llvm-20.1.0
|
||||||
|
cmake -G Ninja -DMLIR_DIR=$LLVM_DIR/lib/cmake/mlir ..
|
||||||
|
```
|
||||||
|
|
||||||
|
可以顺利通过编译。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 启用测试
|
||||||
|
|
||||||
|
但是测试还是非常重要的。我们尝试启动测试看看,取消对于测试文件夹的注释:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm -rf build && mkdir build && cd build
|
||||||
|
cmake -G Ninja -DMLIR_DIR=$LLVM_DIR/lib/cmake/mlir ..
|
||||||
|
```
|
||||||
|
|
||||||
|
很好顺利报错,报错的提示是缺失`FileCheck`、`count`和`not`。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
那么按照`README.md`中的提示添加上来自构建目录的`llvm-lit`会怎么样呢?
|
||||||
|
|
||||||
|
```shell
|
||||||
|
rm -rf build && mkdir build && cd build
|
||||||
|
export LLVM_BUILD_DIR=/home/ricardo/Downloads/llvm-project-20.1.0.src/build
|
||||||
|
cmake -G Ninja -DMLIR_DIR=$LLVM_DIR/lib/cmake/mlir -DLLVM_EXTERNAL_LIT=$LLVM_BUILD_DIR/bin/llvm-lit ..
|
||||||
|
```
|
||||||
|
|
||||||
|
同样的报错,看来问题不是出在这里。
|
||||||
|
|
||||||
|
经过对于LLVM文档的仔细研究,发现原来是没有启动这个变量:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
遂修改最初的LLVM编译指令。
|
||||||
|
|
||||||
|
重新运行来自`README.md`的构建文件生成指令之后,测试也完美运行通过:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
ninja test-standalone
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
不过这个还是有一点令我不是特别满意,这依赖了一个来自于构建目录的工具`llvm-lit`,如果我编译安装的时候眼疾手快的删除了编译目录不就完蛋了。而且我都**standalone**了还依赖似乎有点说不过去?
|
||||||
|
|
||||||
|
于是发现了一篇从`pip`上下载使用`llvm-lit`的[博客](https://medium.com/@mshockwave/using-llvm-lit-out-of-tree-5cddada85a78)和一个LLVM Discourse上面的[帖子](https://discourse.llvm.org/t/running-llvm-lit-on-external-project-test-file-derived-from-standalone-fails/67787),遂进行尝试。
|
||||||
|
|
||||||
|
首先在当前目录下创建一个虚拟环境,并下载安装`llvm-lit`。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
python -m venv .llvm-lit
|
||||||
|
source .llvm-lit/bin/activate
|
||||||
|
pip install lit
|
||||||
|
```
|
||||||
|
|
||||||
|
~~不过这个库似乎没有提供运行入口点,需要我们手动创建一个可执行的`python`文件:~~
|
||||||
|
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from lit.main import main
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
经哥们纠正说`lit`包在某个版本之后会安装`lit`的可执行文件,在安装之后可以直接在命令行调用`lit`。因此在激活虚拟环境之后,`cmake`中直接在`LLVM_EXTERNAL_LIT`配置为`$(which lit)`即可。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cmake -G Ninja -DMLIR_DIR=$LLVM_DIR/lib/cmake/mlir -DLLVM_EXTERNAL_LIT=$(which lit) ..
|
||||||
|
ninja test-standalone
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319192618697.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319192618697.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319194742171.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319194742171.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319202218503.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319202218503.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319202553644.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319202553644.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319204057832.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319204057832.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319204522857.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319204522857.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319205520649.png
(Stored with Git LFS)
Normal file
BIN
YaeBlog/source/posts/mlir-standalone/image-20250319205520649.png
(Stored with Git LFS)
Normal file
Binary file not shown.
117
YaeBlog/source/posts/msbuild-generate-files.md
Normal file
117
YaeBlog/source/posts/msbuild-generate-files.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
title: 如何在MSBuild中复制生成的文件到发布目录中
|
||||||
|
date: 2025-03-20T22:33:21.6955385+08:00
|
||||||
|
tags:
|
||||||
|
- 技术笔记
|
||||||
|
- dotnet
|
||||||
|
---
|
||||||
|
|
||||||
|
如何使用`MSBuild`将构建过程中生成文件复制到生成目录中?
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
### 遇到的问题
|
||||||
|
|
||||||
|
最近在尝试在`blazor`项目中使用`tailwindcss`作为`css`工具类的提供工具,而不是使用老旧的`bootstrap`框架,不过使用`tailwindcss`需要在项目构建时使用`tailwindcss`工具扫描文件中使用到的`css`属性并生成最终的`css`文件,这就带来了在构建时运行`tailwindcss`生成并复制到输出目录的需求。
|
||||||
|
|
||||||
|
由于我是使用`pnpm`作为前端管理工具,我在项目的`csproj`文件中添加了下面的`Target`来生成文件:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Target Name="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
|
<Message Importance="low" Text="Ensure pnpm is installed..."/>
|
||||||
|
<Exec Command="pnpm --version" ContinueOnError="true">
|
||||||
|
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
|
||||||
|
</Exec>
|
||||||
|
|
||||||
|
<Error Condition="$(ErrorCode) != 0" Text="Pnpm is not installed which is required for build."/>
|
||||||
|
|
||||||
|
<Message Importance="normal" Text="Installing pakages using pnpm..."/>
|
||||||
|
<Exec Command="pnpm install"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="TailwindGenerate" AfterTargets="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
|
<Message Importance="normal" Text="Generate css files using tailwind..."/>
|
||||||
|
<Exec Command="pnpm tailwindcss -i wwwroot/tailwind.css -o wwwroot/tailwind.g.css"/>
|
||||||
|
</Target>
|
||||||
|
```
|
||||||
|
|
||||||
|
这套生成逻辑在本地工作良好,但是却在CI上运行时出现了问题:`CI`上打包的`Docker`镜像中没有`tailwind.g.css`文件,导致最终部署的站点丢失了所有的格式。
|
||||||
|
|
||||||
|
### 产生问题的原因
|
||||||
|
|
||||||
|
经过反复实验,我发现只有在构建之前`wwwroot`目录中已经存在`tailwind.g.css`文件的情况下,`MSBuild`才会将生成的文件复制到最终的输出目录中。但是在`CI`环境下,因为使用`.gitignore`没有将`*.g.css`文件添加到代码管理,因此`CI`运行构建之前没有该文件,因此构建的结果中也没有该文件。
|
||||||
|
|
||||||
|
仔细研究`MSBuild`的文档和网络上的[分享](https://gist.github.com/BenVillalobos/c671baa1e32127f4ab582a5abd66b005),我意识到这是由于`MSBuild`的构建流程导致的,MSBuild`的构建流程分成两个大的阶段:
|
||||||
|
|
||||||
|
- 评估阶段(Evaluation Phase)
|
||||||
|
|
||||||
|
在这个阶段,`MSBuild`将会运行读取所有的配置文件,创建需要的属性,展开所有的`glob`,建立好整个构建流程。
|
||||||
|
|
||||||
|
- 执行阶段(Execution Phase)
|
||||||
|
|
||||||
|
在这个阶段,`MSBuild`将按照上一阶段执行的属性执行实际的构建指令。
|
||||||
|
|
||||||
|
这两个阶段的划分就导致在生成阶段才生成的文件不会被包含在复制文件的指令中,因此他们不会被拷贝到最终的输出目录中。
|
||||||
|
|
||||||
|
>这和`cmake`的构建过程很像,首先调用`cmake`生成一些构建指令,在调用实际的构建指令构建二进制文件。
|
||||||
|
|
||||||
|
因此这类问题的推荐解决办法是手动将这些文件添加到构建流程中,即在`BeforeBuild`目标调用之前使用`Content`和`None`等项。
|
||||||
|
|
||||||
|
### 解决问题
|
||||||
|
|
||||||
|
总结上述的解决问题方法,我在上面的构建流程中添加了如下的`None`项:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Target Name="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
|
<Message Importance="low" Text="Ensure pnpm is installed..."/>
|
||||||
|
<Exec Command="pnpm --version" ContinueOnError="true">
|
||||||
|
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
|
||||||
|
</Exec>
|
||||||
|
|
||||||
|
<Error Condition="$(ErrorCode) != 0" Text="Pnpm is not installed which is required for build."/>
|
||||||
|
|
||||||
|
<Message Importance="normal" Text="Installing pakages using pnpm..."/>
|
||||||
|
<Exec Command="pnpm install"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="TailwindGenerate" AfterTargets="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
|
<Message Importance="normal" Text="Generate css files using tailwind..."/>
|
||||||
|
<Exec Command="pnpm tailwindcss -i wwwroot/tailwind.css -o wwwroot/tailwind.g.css"/>
|
||||||
|
|
||||||
|
<!-- Make sure generated file will be copied to output directory-->
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="wwwroot/tailwind.g.css" Visible="false" CopyToOutputDirectory="PreserveNewest"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
```
|
||||||
|
|
||||||
|
在运行构建之后,在最终的`publish`文件夹的`wwroot`文件夹中就可以找到`tailwind.g.css`文件。
|
||||||
|
|
||||||
|
不过我还想进行一点优化,`MSBuild`文档中建议将自动生成的文件放在`IntermediateOutputPath`,也就是`obj`文件加中,因此这里尝试将`tailwind.g.css`文件生成到`IntermediateOuputPath`中,优化之后的`Target`项长这个样子:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Target Name="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
|
<Message Importance="low" Text="Ensure pnpm is installed..."/>
|
||||||
|
<Exec Command="pnpm --version" ContinueOnError="true">
|
||||||
|
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
|
||||||
|
</Exec>
|
||||||
|
|
||||||
|
<Error Condition="$(ErrorCode) != 0" Text="Pnpm is not installed which is required for build."/>
|
||||||
|
|
||||||
|
<Message Importance="normal" Text="Installing pakages using pnpm..."/>
|
||||||
|
<Exec Command="pnpm install"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="TailwindGenerate" AfterTargets="EnsurePnpmInstalled" BeforeTargets="BeforeBuild">
|
||||||
|
<Message Importance="normal" Text="Generate css files using tailwind..."/>
|
||||||
|
<Exec Command="pnpm tailwindcss -i wwwroot/tailwind.css -o $(IntermediateOutputPath)tailwind.g.css"/>
|
||||||
|
|
||||||
|
<!-- Make sure generated file will be copied to output directory-->
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="$(IntermediateOutputPath)tailwind.g.css" Visible="false" TargetPath="wwwroot/tailwind.g.css"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
```
|
||||||
|
|
||||||
|
经过测试,这套生成逻辑在`blazor`类库环境下也可以正常运行,类库的文件会被正确地生成到`wwwroot/_content/<ProjectName>/`文件夹下面。
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
content: ["**/*.razor", "**/*.cshtml", "**/*.html", "Processors/EssayStylesPostRenderProcessor.cs"],
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
Binary file not shown.
BIN
YaeBlog/wwwroot/fonts/bootstrap-icons.woff2
(Stored with Git LFS)
BIN
YaeBlog/wwwroot/fonts/bootstrap-icons.woff2
(Stored with Git LFS)
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
1
YaeBlog/wwwroot/tailwind.css
Normal file
1
YaeBlog/wwwroot/tailwind.css
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
Reference in New Issue
Block a user