Skip to content

Commit

Permalink
Merge pull request #289 from RyoJerryYu/refactor/building-phase-refactor
Browse files Browse the repository at this point in the history
Refactor/building phase refactor
  • Loading branch information
RyoJerryYu authored Apr 27, 2024
2 parents 5371c77 + 8dc33fa commit 338cf59
Show file tree
Hide file tree
Showing 57 changed files with 1,873 additions and 881 deletions.
10 changes: 4 additions & 6 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
}
"command": "npm run dev"
},
]
}
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const customJestConfig = {
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules', '<rootDir>/'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
testEnvironment: 'jest-environment-jsdom',
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"scripts": {
"dev": "next dev",
"test": "jest",
"test-ci": "TEST_ENV=ci jest",
"build": "next build && next export",
"postbuild": "next-sitemap",
"start": "next start",
Expand Down
6 changes: 4 additions & 2 deletions public/content/articles/2020-01-27-Building-this-blog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
created_at: 2020-01-27 14:00:00
updated_at: 2022-03-27 21:30:33+08:00
updated_at: 2024-04-16 21:30:33+08:00
layout: post
title: "搭建博客的过程"
subtitle: "记录这个博客搭建的过程,以及遇到的坑。"
Expand Down Expand Up @@ -217,7 +217,8 @@ README.md为Github仓库的介绍,可以在README.md中写上这个博客主
文章主要放在_posts文件夹中,用`git push`的方式推送到GitHub仓库,即可完成文章上传。

文章正文以**markdown**语法书写,在文本头部增加如下格式的信息:
```

```yaml
---
layout: post
title: "Welcome to Ryo's Blog!"
Expand All @@ -230,6 +231,7 @@ tags:
- 杂谈
---
```

其中:
- `layout`为文章所用的模板,可选`post`或`keynote`,也可自己写一个模板html放在`_layouts`文件夹下。
- `title`为文章标题,`subtitle`为文章副标题。
Expand Down
14 changes: 9 additions & 5 deletions src/components/Post/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PrevNextInfo } from "@/statics";
import { PostMeta } from "@/statics/loader";
import { TagInfo } from "@/statics/tag-index";
import { PrevNextInfo } from "@/core/indexing/index-building/prev-next-index-builder";
import { TagInfo } from "@/core/indexing/index-building/tag-index-builder";
import { PostMeta } from "@/core/types/indexing";
import clsx from "clsx";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import Link from "next/link";
Expand Down Expand Up @@ -37,12 +37,16 @@ const Post = ({ meta, source, tags, prevNextInfo }: PostProps) => {
<div className="mt-4 mb-4 flex justify-center">
{prevInfo && (
<div className="ml-0 mr-auto">
<Link href={prevInfo.path}>{`<- ${prevInfo.title}`}</Link>
<Link
href={prevInfo.pathMapping.pagePath}
>{`<- ${prevInfo.meta.title}`}</Link>
</div>
)}
{nextInfo && (
<div className="mr-0 ml-auto">
<Link href={nextInfo.path}>{`${nextInfo.title} ->`}</Link>
<Link
href={nextInfo.pathMapping.pagePath}
>{`${nextInfo.meta.title} ->`}</Link>
</div>
)}
</div>
Expand Down
23 changes: 7 additions & 16 deletions src/components/PostList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Post } from "@/statics";
import { PostMeta } from "@/statics/loader";
import { TagInfo } from "@/statics/tag-index";
import { TagInfo } from "@/core/indexing/index-building/tag-index-builder";
import { PostMeta, PostResource } from "@/core/types/indexing";
import Link from "next/link";
import React from "react";
import RelativeTime from "../RelativeTime";
Expand Down Expand Up @@ -40,13 +39,6 @@ export function PostListElement({
url,
tags,
}: PostListElementProps) {
const renderTags = () => {
if (!postMeta.tags || postMeta.tags.length === 0) {
return null;
}
return;
};

return (
<div className={className}>
<Link href={url}>
Expand All @@ -70,18 +62,17 @@ export function PostListElement({
}

type PostListProps = {
posts: Post[];
posts: PostResource[];
allTags: Map<string, TagInfo>; // Map<tag, TagInfo>
getUrl?: (post: Post) => string;
};

export default function PostList({ posts, getUrl, allTags }: PostListProps) {
export default function PostList({ posts, allTags }: PostListProps) {
if (posts.length === 0) {
return <div>No posts</div>;
}

const elementsProps = posts.map((post) => {
const url = getUrl ? getUrl(post) : `/posts/${post.slug}`;
const pagePath = post.pathMapping.pagePath;
const tags = post.meta.tags.map((tag): TagInfo => {
const tagInfo = allTags.get(tag);
if (!tagInfo) {
Expand All @@ -97,7 +88,7 @@ export default function PostList({ posts, getUrl, allTags }: PostListProps) {

return {
post: post,
url: url,
url: pagePath,
tags: tags,
};
});
Expand All @@ -106,7 +97,7 @@ export default function PostList({ posts, getUrl, allTags }: PostListProps) {
<div className={style.postList}>
{elementsProps.map(({ post, url, tags }) => (
<PostListElement
key={post.slug}
key={post.pathMapping.pagePath}
className={style.postListElement}
postMeta={post.meta}
tags={tags}
Expand Down
2 changes: 1 addition & 1 deletion src/components/TagSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TagInfo } from "@/statics/tag-index";
import { TagInfo } from "@/core/indexing/index-building/tag-index-builder";
import TagsBox from "./TagsBox";

export type TagSelectorProps = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/TagsBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TagInfo } from "@/statics/tag-index";
import { TagInfo } from "@/core/indexing/index-building/tag-index-builder";
import clsx from "clsx";
import Link from "next/link";
import style from "./TagsBox.module.scss";
Expand Down
96 changes: 96 additions & 0 deletions src/core/indexing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# `core/indexing`

## Terms

example:

Consider an `.md` file `public/content/articles/2020-02-02-hello-world.md`:

- The page could be accessed by `https://xx.xx.x/articles/hello-world` is a `Page`. What this page shows is the content of the `Post`.
- `https://xx.xx.x/articles` is also a `Page`, but it is not a `Post`.
- The static resource could be accessed by `https://xx.xx.x/content/articles/2020-02-02-hello-world.md` is not a `Page`, but a static resource.
- The `filePath` is `public/content/articles/2020-02-02-hello-world.md`.
- The `pagePath` is `/articles/hello-world`.
- The `slug` is `hello-world`.

### Resource

Anything that could be accessed by the browser, including pages and static resources.
A resource would have a path mapping and a meta data.

### Page

Represent a page on the website. It should be rendered by a Next.js page component.
Not all pages related to a file. e.g. the article list page is not related to any file.

### Post

Represent a post, which can be an article or an idea.
A post should have a page to show it's content, and should have a file to store it's content.

### Static Resource

A file that could be accessed by the browser, but not rendered by a Next.js.
Mostly a static resource related to a file.
e.g. images, markdown files, etc.

### filePath

The path to a static file, should be available for `fs.readFileSync(filePath, "utf-8")`.

Mostly relative to the project root directory, start with `public/`.

### pagePath

The path of a page on the website, related from `SITE_BASE_PATH`. Always start with `/`.

Could be accessible from the browser by `${SITE_BASE_PATH}${pagePath}`.

### slug

The path argument used for a page.

e.g. For `src/pages/articles/[slug].tsx`, for the post of `/articles/hello-world`, the slug is `hello-world`.

For one type of post (article or ideas), the slug should be unique for a post.

Should have no any `/` in the slug.

Not only a post should could have a slug. e.g. a tag page could have a slug too.

### meta

One resource on the site may have it's own meta data.
Different types of resources may have different type of meta data.
Meta should only related to the resource itself, never care about the other resources.

### index

Any other things that needed for rendering pages.
Mostly depends on all metas and paths. Not related to one specific resource.
Mostly do not need to fetch extra data, but it could if needed.

Something should be an index:

- tag list and post list for a tag
- short alias reference to another resource
- reverse reference
- post list in order and prev/next post
- clip data list (need to fetch data)

Something should not be an index:

- post tag in frontmatter and in content
- post full path
- outgoing reference in a post content
- Any thing that could directly get from content should not be an index.



# TODO

名称不对, path mapping 没有做真正的 mapping 工作,与外部 mapping 重名
- path-resolving, ResourcePath, Resolver


pipeline -> ResourceList
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AliasIndexBuilder } from "./alias-index";
import { AliasIndexBuilder } from "./alias-index-builder";

describe("test alias index", () => {
const input = [
Expand All @@ -7,9 +7,15 @@ describe("test alias index", () => {
];
const builder = new AliasIndexBuilder();
input.forEach((item) => {
builder.add(item.path);
builder.addResource("articles", {
pathMapping: {
pagePath: item.path,
filePath: "do not care",
},
meta: {},
});
});
const index = builder.build();
const futureIndex = builder.buildIndex();

const resolveCases = [
{
Expand All @@ -23,7 +29,8 @@ describe("test alias index", () => {
{ name: "# path without layers", alias: "2020-01-01-Blog-01.jpg" },
// { name: "# path without date", alias: "Blog-01.jpg" }, # not implemented yet
];
it.each(resolveCases)("resolve not md $name", ({ alias }) => {
it.each(resolveCases)("resolve not md $name", async ({ alias }) => {
const { alias: index } = await futureIndex;
const path = index.resolve(alias);
expect(path).not.toBeUndefined();
});
Expand Down Expand Up @@ -53,7 +60,8 @@ describe("test alias index", () => {
},
// { name: "path without date and extension", alias: "Blog-02" }, # not implemented yet
];
it.each(resolveMDCases)("resolve md $name", ({ alias }) => {
it.each(resolveMDCases)("resolve md $name", async ({ alias }) => {
const { alias: index } = await futureIndex;
const path = index.resolve(alias);
expect(path).not.toBeUndefined();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

import { glob } from "glob";
import path from "path";
import { BaseMeta, BasePathMapping, Resource } from "../../types/indexing";
import { IndexBuilder, getIndexFromIndexPool } from "./index-building";

export function listAllStaticFiles() {
return glob.sync("public/content/**/*.*");
Expand All @@ -42,17 +44,17 @@ const isPages = (urlpath: string) => {
// aliasesFromPath: get all aliases from a path
// path should pass from post cache, which already parsed and resolvable
// path should always start with `/`
export const aliasesFromPath = (path: string) => {
const parts = path.split("/");
export const aliasesFromPagePath = (pagePath: string) => {
const parts = pagePath.split("/");
if (parts[0] === "") {
parts.shift(); // always
}
const aliases: string[] = [];
const needAppendMd = isPages(path);
const needAppendMd = isPages(pagePath);

aliases.push(path); // full path, e.g. /articles/2020-01-27-Building-this-blog
aliases.push(pagePath); // full path, e.g. /articles/2020-01-27-Building-this-blog
if (needAppendMd) {
aliases.push(path.concat(".md"));
aliases.push(pagePath.concat(".md"));
}
for (let i = 0; i < parts.length; i++) {
aliases.push(parts.slice(i).join("/"));
Expand All @@ -63,36 +65,42 @@ export const aliasesFromPath = (path: string) => {
return aliases;
};

export class AliasIndexBuilder {
export class AliasIndexBuilder
implements IndexBuilder<BasePathMapping, BaseMeta, AliasIndex, "alias">
{
// alias -> path
private readonly index: Map<string, string>;
constructor() {
this.index = new Map();
}

add = (path: string) => {
const aliases = aliasesFromPath(path);
addResource = (
resourceType: string,
resource: Resource<BasePathMapping, BaseMeta>
) => {
const { pagePath } = resource.pathMapping;
const aliases = aliasesFromPagePath(pagePath);
for (const alias of aliases) {
if (!this.index.has(alias)) {
// first add posts, then add static contents
// .md static files would resolved to pages
this.index.set(alias, path);
this.index.set(alias, pagePath);
continue;
}

if (this.index.get(alias) === path) {
if (this.index.get(alias) === pagePath) {
continue;
}
console.log(
`Alias ${alias} already exists, path: ${this.index.get(
alias
)}, new path: ${path}`
)}, new path: ${pagePath}`
);
}
};

build = () => {
return new AliasIndex(this.index);
buildIndex = async (): Promise<{ alias: AliasIndex }> => {
return {
alias: new AliasIndex(this.index),
};
};
}

Expand All @@ -105,4 +113,6 @@ export class AliasIndex {
resolve = (alias: string) => {
return this.index.get(alias);
};

static fromPool = getIndexFromIndexPool<AliasIndex>("alias");
}
Loading

0 comments on commit 338cf59

Please sign in to comment.