Skip to content

Commit 0c0c596

Browse files
committed
refactor: 将 VuePress 配置迁至仓库根并拆分站点模块
站点配置拆为 site/sidebar/seo/footer;侧栏 `.md` 经 `sidebar.resolve` 对齐 permalink;构建产物路径同步更新 CI/Dockerfile,并升级 `@142vip` 依赖。
1 parent a37eaeb commit 0c0c596

24 files changed

Lines changed: 2922 additions & 2021 deletions

‎.github/workflows/CD.yaml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ jobs:
6060
./scripts/ci
6161
6262
# 编译 打包成dist
63-
- name: Build with VitePress
63+
- name: Build with VuePress
6464
run: pnpm build:proxy
6565

6666
- name: Upload artifact
6767
uses: actions/upload-pages-artifact@v3
6868
with:
69-
path: docs/.vuepress/dist
69+
path: .vuepress/dist
7070

7171
# 部署
7272
- name: Deploy to GitHub Pages

‎.github/workflows/CI.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
# 缓存
5858
cache: pnpm
5959

60-
# 下载依赖,并执行初始化脚本:钩子函数、思维导图构建
60+
# 下载依赖并执行初始化脚本
6161
- name: Install Dependencies
6262
run: |
6363
./scripts/ci

‎.gitignore‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ node_modules/
1515
.next
1616
.nuxt
1717
dist
18+
.vuepress/dist
19+
.vuepress/.temp
20+
.vuepress/.cache
21+
docs/.vuepress/dist
22+
docs/.vuepress/.temp
23+
docs/.vuepress/.cache
24+
.vercel

‎.vuepress/config/footer.ts‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { OPEN_SOURCE_ADDRESS, OPEN_SOURCE_AUTHOR } from '@142vip/open-source'
2+
import { pkg } from './site'
3+
4+
/** 页脚 HTML */
5+
export const footerHtmlStr = `
6+
<div>
7+
All Rights Reserved
8+
<a href="${OPEN_SOURCE_ADDRESS.HOME_PAGE_GITHUB_VIP}" target="_blank">@${OPEN_SOURCE_ADDRESS.GITHUB_ORGANIZATION_NAME}</a> |
9+
<strong>${pkg.name}@v${pkg.version} </strong>
10+
</div>
11+
<div style="margin-top: 5px">
12+
<a href="${OPEN_SOURCE_ADDRESS.BAIDU_STATISTICS_URL}" target="_blank">${OPEN_SOURCE_ADDRESS.BAIDU_STATISTICS_NAME}</a>
13+
<span style="margin: 0 5px;">|</span>
14+
<a href="${OPEN_SOURCE_ADDRESS.BEI_AN_URL}" target="_blank">${OPEN_SOURCE_ADDRESS.BEI_AN_NAME}</a>
15+
</div>
16+
`
17+
18+
/** 版权信息 HTML */
19+
export const copyrightHtmlStr = `
20+
<strong>MIT 协议</strong> | 版权所有 © 2015-${new Date().getFullYear()} ${OPEN_SOURCE_AUTHOR.name}
21+
<div style="margin-top: 10px">
22+
<a
23+
href="${OPEN_SOURCE_ADDRESS.SITE_DEPLOY_JavaScriptCollection_GITHUB}"
24+
target="_blank"
25+
style="padding: 5px"
26+
>
27+
<img
28+
alt="JavaScriptCollection Deploy In Github Pages"
29+
src="https://img.shields.io/badge/github-success-green?logo=github&color=bef9c6"
30+
>
31+
</a>
32+
<a
33+
href="${OPEN_SOURCE_ADDRESS.SITE_DEPLOY_JavaScriptCollection_NETLIFY}"
34+
target="_blank"
35+
style="padding: 5px"
36+
>
37+
<img
38+
alt="JavaScriptCollection Deploy In Netlify"
39+
src="https://img.shields.io/badge/netlify-success-green?logo=netlify&color=bef9c6"
40+
>
41+
</a>
42+
<a
43+
href="${OPEN_SOURCE_ADDRESS.SITE_DEPLOY_JavaScriptCollection_VERCEL}"
44+
target="_blank"
45+
style="padding: 5px"
46+
>
47+
<img
48+
src="https://img.shields.io/badge/vercel-success-green?logo=vercel&color=bef9c6"
49+
alt="JavaScriptCollection Deploy In Vercel"
50+
>
51+
</a>
52+
</div>
53+
`

‎.vuepress/config/index.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/** 站点配置统一导出入口 */
2+
export * from './footer'
3+
export * from './plugins/vite-build.plugin'
4+
export * from './seo'
5+
export * from './sidebar'
6+
export * from './sidebar.resolve'
7+
export * from './site'
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { Plugin } from '@vuepress/core'
2+
import { addViteConfig } from '@vuepress/helper'
3+
4+
/**
5+
* 调整 Vite 构建参数。
6+
* theme-hope 会通过 extendsBundlerOptions 将 chunkSizeWarningLimit 设为 1024,
7+
* 文档站点含 md-enhance / mermaid 等依赖,单 chunk 可达 4MB+,
8+
* 此处将阈值提高到 8192 以消除构建告警(theme-hope 默认为 1024)。
9+
*/
10+
export function viteBuildPlugin(): Plugin {
11+
return {
12+
name: 'vip-vite-build',
13+
extendsBundlerOptions(bundlerOptions, app) {
14+
addViteConfig(bundlerOptions, app, {
15+
build: {
16+
chunkSizeWarningLimit: 8192,
17+
},
18+
})
19+
},
20+
}
21+
}

‎.vuepress/config/seo.ts‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type { UserConfig } from '@vuepress/cli'
2+
import { OPEN_SOURCE_AUTHOR } from '@142vip/open-source'
3+
import { VipNodeJS } from '@142vip/utils'
4+
import {
5+
homeUrl,
6+
siteDescription,
7+
siteLogo,
8+
siteLogoUrl,
9+
siteTitle,
10+
} from './site'
11+
12+
/** JavaScript / 全栈开发相关 SEO 关键词 */
13+
const siteKeywords = [
14+
'JavaScript',
15+
'Node.js',
16+
'TypeScript',
17+
'前端开发',
18+
'后端开发',
19+
'算法',
20+
'面试八股',
21+
'Vue',
22+
'Express',
23+
'Koa',
24+
'微服务',
25+
'Docker',
26+
].join(', ')
27+
28+
/**
29+
* SEO 相关 head 标签(关键词、Open Graph、Twitter Card 等)
30+
*/
31+
export const seoHead: NonNullable<UserConfig['head']> = [
32+
['meta', { name: 'description', content: siteDescription }],
33+
['meta', { name: 'keywords', content: siteKeywords }],
34+
['meta', { name: 'author', content: OPEN_SOURCE_AUTHOR.name }],
35+
['meta', { name: 'robots', content: 'index,follow,max-image-preview:large' }],
36+
['meta', { name: 'googlebot', content: 'index,follow' }],
37+
['meta', { property: 'og:type', content: 'website' }],
38+
['meta', { property: 'og:site_name', content: siteTitle }],
39+
['meta', { property: 'og:title', content: siteTitle }],
40+
['meta', { property: 'og:description', content: siteDescription }],
41+
['meta', { property: 'og:url', content: homeUrl }],
42+
['meta', { property: 'og:image', content: siteLogoUrl }],
43+
['meta', { property: 'og:locale', content: 'zh_CN' }],
44+
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
45+
['meta', { name: 'twitter:title', content: siteTitle }],
46+
['meta', { name: 'twitter:description', content: siteDescription }],
47+
['meta', { name: 'twitter:image', content: siteLogoUrl }],
48+
['link', { rel: 'canonical', href: homeUrl }],
49+
]
50+
51+
/**
52+
* 站点 head 配置
53+
* - `seoHead`:搜索引擎与社交平台元信息
54+
* - `favicon`:见 `.vuepress/public/`
55+
* - Vercel 统计:仅 Vercel 构建注入
56+
* - 百度统计
57+
*/
58+
export const siteHead: NonNullable<UserConfig['head']> = [
59+
...seoHead,
60+
['link', { rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' }],
61+
['link', { rel: 'apple-touch-icon', href: siteLogo }],
62+
[
63+
'script',
64+
{},
65+
`var _hmt = _hmt || [];
66+
(function() {
67+
var hm = document.createElement("script");
68+
hm.src = "https://hm.baidu.com/hm.js?613c9d7af9e1c9a7f9eef6a55aa2399d";
69+
var s = document.getElementsByTagName("script")[0];
70+
s.parentNode.insertBefore(hm, s);
71+
})();`,
72+
],
73+
]
74+
75+
if (VipNodeJS.getProcessEnv('VERCEL') === '1') {
76+
siteHead.push(['script', { type: 'text/javascript', src: '/_vercel/insights/script.js' }])
77+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import type { AutoLinkOptions, SidebarItemOptions } from 'vuepress-theme-hope'
2+
import { VipNodeJS } from '@142vip/utils'
3+
4+
/** 侧边栏直链项 */
5+
export interface DocsSidebarLink {
6+
text: string
7+
link: string
8+
}
9+
10+
/** 侧边栏分组项 */
11+
export interface DocsSidebarGroup {
12+
text: string
13+
prefix?: string
14+
link?: string
15+
collapsible?: boolean
16+
expanded?: boolean
17+
children: DocsSidebarItem[]
18+
}
19+
20+
export type DocsSidebarItem = DocsSidebarLink | DocsSidebarGroup
21+
22+
export type DocsSidebarConfig = DocsSidebarItem[]
23+
24+
function isSidebarGroup(item: DocsSidebarItem): item is DocsSidebarGroup {
25+
return Array.isArray((item as DocsSidebarGroup).children)
26+
}
27+
28+
function readPermalink(mdFilePath: string): string | null {
29+
if (!VipNodeJS.existPath(mdFilePath)) {
30+
return null
31+
}
32+
33+
for (const line of VipNodeJS.readFileToStrByUTF8(mdFilePath).split('\n')) {
34+
if (line.startsWith('permalink:')) {
35+
return line.slice('permalink:'.length).trim()
36+
}
37+
}
38+
39+
return null
40+
}
41+
42+
function resolveMdLink(
43+
link: string,
44+
docsBasePath: string,
45+
groupPrefix: string,
46+
): string {
47+
const mdRelativePath = groupPrefix
48+
? `${groupPrefix}/${link}`
49+
: link
50+
const permalink = readPermalink(
51+
VipNodeJS.pathJoin(VipNodeJS.getProcessCwd(), 'docs', docsBasePath, mdRelativePath),
52+
)
53+
54+
return permalink ?? link
55+
}
56+
57+
/**
58+
* Hope 手动 sidebar 的 `.md` 链接按「prefix + 文件名」推断路由,**不会**读取 frontmatter `permalink`。
59+
* 本仓库大量页面 permalink 与文件名不一致(如 `html.md` → `/front-end/base-begin/html-correlation.html`),
60+
* 故在配置阶段按文件解析并替换 `link`;无法单靠 `vuepress.config.ts` 原生选项完成。
61+
*
62+
* @param sidebar 模块侧边栏原始配置(可含 `.md` 链接)
63+
* @param docsBasePath `docs/` 下的相对目录,如 `server-end/framework/egg`
64+
*/
65+
export function resolveSidebarPermalinks(
66+
sidebar: DocsSidebarConfig,
67+
docsBasePath: string,
68+
): SidebarItemOptions[] {
69+
const walk = (items: DocsSidebarItem[], groupPrefix = ''): SidebarItemOptions[] =>
70+
items.map((item) => {
71+
if (isSidebarGroup(item)) {
72+
return {
73+
...item,
74+
children: walk(item.children, item.prefix ?? ''),
75+
}
76+
}
77+
78+
if (!item.link.endsWith('.md')) {
79+
return item as AutoLinkOptions
80+
}
81+
82+
return {
83+
...item,
84+
link: resolveMdLink(item.link, docsBasePath, groupPrefix),
85+
}
86+
})
87+
88+
return walk(sidebar)
89+
}

‎.vuepress/config/sidebar.ts‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { OPEN_SOURCE_ADDRESS } from '@142vip/open-source'
2+
import { defineVipNavbarConfig, defineVipSidebarConfig } from '@142vip/vuepress'
3+
import { BattleInterviewSidebar } from '../../docs/battle-interview/battle-interview.sidebar'
4+
import { DevelopSkillSidebar } from '../../docs/develop-skill/develop-skill.sidebar'
5+
import { FrontEndSidebar } from '../../docs/front-end/front-end.sidebar'
6+
import { JobChanceSidebar } from '../../docs/job-chance/job-chance.sidebar'
7+
import { MicroserviceSidebar } from '../../docs/microservice/microserviceSidebar'
8+
import { ReadBooksSidebar } from '../../docs/read-books/read-books.sidebar'
9+
import {
10+
BaseSidebar,
11+
DesignPatternsSidebar,
12+
EggSidebar,
13+
ExpressSidebar,
14+
KoaSidebar,
15+
LinuxSidebar,
16+
MongoSideBar,
17+
MySqlSideBar,
18+
NodeLearnSidebar,
19+
RedisSidebar,
20+
SequelizeOrmSidebar,
21+
ServerEndSidebar,
22+
TypeormSidebar,
23+
TypescriptSidebar,
24+
} from '../../docs/server-end'
25+
import { soloAlgorithmSidebar } from '../../docs/solo-algorithm/solo-algorithm.sidebar'
26+
import { resolveSidebarPermalinks } from './sidebar.resolve'
27+
28+
/** 顶部导航栏 */
29+
export const navbarConfig = defineVipNavbarConfig([
30+
{ text: '🔥 首页', link: '/' },
31+
{ text: '🧠 SOLO算法', children: soloAlgorithmSidebar },
32+
{ text: '💡 Battle面试官', link: '/battle-interview/' },
33+
{
34+
text: '💻 全栈开发',
35+
children: [
36+
{ text: '👩🏻‍💻 前端', link: '/front-end/' },
37+
{ text: '👨🏻‍💻 后端', link: '/server-end/' },
38+
{ text: '💫 开发技巧', link: '/develop-skill/' },
39+
{ text: '🕸️ 微服务架构', link: '/microservice/' },
40+
],
41+
},
42+
{ text: '📖 读书整理', link: '/read-books/' },
43+
{
44+
text: '👉 了解更多',
45+
children: [
46+
{ text: '📄 变更记录', link: '/changelog.md' },
47+
{ text: '📣 网站动态', link: '/big-event-history.md' },
48+
{
49+
text: '外链',
50+
children: [
51+
{ text: '🎉 历史版本', link: `${OPEN_SOURCE_ADDRESS.GITHUB_REPO_JSC}/releases` },
52+
{ text: '🎯 开发计划', link: 'https://142vip-cn.feishu.cn/share/base/view/shrcnuuRDWBoHLmYaknXWFuhR4d' },
53+
{ text: '🔗 技术&平台', link: '/frequent-site-link.html' },
54+
{ text: '💥 公众号文章', link: '/wechat-list.md' },
55+
],
56+
},
57+
],
58+
},
59+
])
60+
61+
/**
62+
* 各模块侧边栏
63+
* - 路径键与 Hope 路由前缀一致
64+
* - `.md` 链接通过 `resolveSidebarPermalinks` 自动对齐 frontmatter `permalink`
65+
*/
66+
export const sidebarConfig = defineVipSidebarConfig({
67+
'/front-end': resolveSidebarPermalinks(FrontEndSidebar, 'front-end'),
68+
'/server-end': resolveSidebarPermalinks(ServerEndSidebar, 'server-end'),
69+
'/server-end/framework/egg-tutorial': resolveSidebarPermalinks(EggSidebar, 'server-end/framework/egg'),
70+
'/server-end/framework/koa-tutorial': resolveSidebarPermalinks(KoaSidebar, 'server-end/framework/koa'),
71+
'/server-end/framework/express-tutorial': resolveSidebarPermalinks(ExpressSidebar, 'server-end/framework/express'),
72+
'/server-end/database/redis': resolveSidebarPermalinks(RedisSidebar, 'server-end/database/redis'),
73+
'/server-end/database/mysql': resolveSidebarPermalinks(MySqlSideBar, 'server-end/database/mysql'),
74+
'/server-end/database/mongo': resolveSidebarPermalinks(MongoSideBar, 'server-end/database/mongo'),
75+
'/server-end/linux': resolveSidebarPermalinks(LinuxSidebar, 'server-end/linux'),
76+
'/server-end/design-patterns': resolveSidebarPermalinks(DesignPatternsSidebar, 'server-end/design-patterns'),
77+
'/server-end/typescript': resolveSidebarPermalinks(TypescriptSidebar, 'server-end/typescript'),
78+
'/server-end/base': resolveSidebarPermalinks(BaseSidebar, 'server-end/base'),
79+
'/server-end/node-learn': resolveSidebarPermalinks(NodeLearnSidebar, 'server-end/node-learn'),
80+
'/server-end/orm/sequelize': resolveSidebarPermalinks(SequelizeOrmSidebar, 'server-end/orm/sequelize'),
81+
'/server-end/orm/typeorm': resolveSidebarPermalinks(TypeormSidebar, 'server-end/orm/typeorm'),
82+
'/develop-skill': resolveSidebarPermalinks(DevelopSkillSidebar, 'develop-skill'),
83+
'/solo-algorithm': resolveSidebarPermalinks(soloAlgorithmSidebar, 'solo-algorithm'),
84+
'/read-books': resolveSidebarPermalinks(ReadBooksSidebar, 'read-books'),
85+
'/job-chance': resolveSidebarPermalinks(JobChanceSidebar, 'job-chance'),
86+
'/microservice': resolveSidebarPermalinks(MicroserviceSidebar, 'microservice'),
87+
'/battle-interview': resolveSidebarPermalinks(BattleInterviewSidebar, 'battle-interview'),
88+
})

0 commit comments

Comments
 (0)