valaxy 0.5.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/{dist/types/index.mjs → client/app/data.ts} +0 -0
- package/client/components/PostCard.vue +4 -2
- package/client/components/ValaxyBg.vue +1 -1
- package/client/components/ValaxyFooter.vue +1 -1
- package/client/components/ValaxyMd.vue +34 -27
- package/client/components/ValaxyToc.vue +3 -3
- package/client/composables/copy-code.ts +92 -0
- package/client/composables/outline.ts +168 -0
- package/client/composables/sidebar.ts +46 -1
- package/client/config.ts +30 -7
- package/client/main.ts +4 -1
- package/client/modules/valaxy.ts +19 -7
- package/client/shims.d.ts +6 -1
- package/client/styles/common/code.scss +191 -167
- package/client/styles/common/markdown.scss +0 -2
- package/client/styles/css-vars.scss +30 -7
- package/client/styles/palette.scss +21 -2
- package/client/styles/vars.scss +32 -18
- package/client/utils/helper.ts +22 -0
- package/client/utils/sidebar.ts +26 -0
- package/config/index.ts +18 -0
- package/dist/chunk-23IW567G.mjs +40 -0
- package/dist/chunk-YUC5WP5Y.js +40 -0
- package/dist/{config-7bd43d41.d.ts → config-112ac884.d.ts} +15 -4
- package/dist/index.d.ts +361 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/node/cli.js +7 -11
- package/dist/node/cli.mjs +7 -11
- package/dist/node/index.d.ts +3 -2
- package/dist/node/index.js +1 -1
- package/dist/node/index.mjs +1 -1
- package/index.ts +3 -0
- package/node/config.ts +9 -23
- package/node/markdown/highlight.ts +27 -39
- package/node/markdown/index.ts +30 -16
- package/node/markdown/markdown-it/highlightLines.ts +1 -1
- package/node/markdown/markdownToVue.ts +275 -0
- package/node/options.ts +16 -0
- package/node/plugins/extendConfig.ts +4 -3
- package/node/plugins/index.ts +104 -7
- package/node/plugins/preset.ts +8 -8
- package/node/rss.ts +1 -1
- package/node/shims.d.ts +0 -5
- package/node/utils/getGitTimestamp.ts +13 -0
- package/node/utils/index.ts +11 -0
- package/package.json +20 -9
- package/shared/index.ts +1 -0
- package/tsup.config.ts +5 -3
- package/types/config.ts +7 -4
- package/types/data.ts +31 -0
- package/types/index.ts +1 -0
- package/types/posts.ts +1 -1
- package/dist/chunk-RSQONJW3.mjs +0 -86
- package/dist/chunk-XQIGHIAX.js +0 -86
- package/dist/client/index.d.ts +0 -188
- package/dist/client/index.js +0 -1
- package/dist/client/index.mjs +0 -1
- package/dist/posts-32f55e33.d.ts +0 -117
- package/dist/types/index.d.ts +0 -8
- package/dist/types/index.js +0 -1
- package/index.d.ts +0 -3
- package/node/plugins/markdown.ts +0 -54
package/dist/node/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as vite from 'vite';
|
|
2
2
|
import { InlineConfig } from 'vite';
|
|
3
|
-
import { V as ValaxyConfig } from '../config-
|
|
3
|
+
import { V as ValaxyConfig } from '../config-112ac884.js';
|
|
4
4
|
import 'type-fest';
|
|
5
5
|
import 'unocss/vite';
|
|
6
|
-
import 'vite-plugin-md';
|
|
7
6
|
import 'markdown-it';
|
|
7
|
+
import 'shiki';
|
|
8
8
|
import 'markdown-it-anchor';
|
|
9
9
|
import 'katex';
|
|
10
10
|
|
|
@@ -36,6 +36,7 @@ interface ResolvedValaxyOptions {
|
|
|
36
36
|
* config file path
|
|
37
37
|
*/
|
|
38
38
|
configFile: string;
|
|
39
|
+
pages: string[];
|
|
39
40
|
}
|
|
40
41
|
interface ValaxyServerOptions {
|
|
41
42
|
onConfigReload?: (newConfig: ValaxyConfig, config: ValaxyConfig) => void;
|
package/dist/node/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkYUC5WP5Yjs = require('../chunk-YUC5WP5Y.js');require('../chunk-U5OMNIOK.js');exports.createServer = _chunkYUC5WP5Yjs.f;
|
package/dist/node/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{f as o}from"../chunk-23IW567G.mjs";import"../chunk-EAN2KU6W.mjs";export{o as createServer};
|
package/index.ts
ADDED
package/node/config.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
import fs from 'fs'
|
|
3
3
|
import { loadConfig } from 'unconfig'
|
|
4
4
|
import defu from 'defu'
|
|
5
|
-
import type {
|
|
6
|
-
import type { UserConfig, ValaxyConfig } from '../types'
|
|
5
|
+
import type { ValaxyConfig } from '../types'
|
|
7
6
|
import type { ValaxyEntryOptions } from './options'
|
|
8
7
|
|
|
9
8
|
const defaultValaxyConfig: ValaxyConfig = {
|
|
10
|
-
url: '',
|
|
9
|
+
url: '/',
|
|
11
10
|
lang: 'en',
|
|
12
11
|
title: 'Valaxy Blog',
|
|
13
12
|
description: 'A blog generated by Valaxy.',
|
|
@@ -22,13 +21,15 @@ const defaultValaxyConfig: ValaxyConfig = {
|
|
|
22
21
|
message: 'All at sea.',
|
|
23
22
|
},
|
|
24
23
|
},
|
|
25
|
-
favicon: 'favicon.svg',
|
|
24
|
+
favicon: '/favicon.svg',
|
|
26
25
|
feed: {
|
|
27
26
|
name: '',
|
|
28
27
|
favicon: 'favicon.svg',
|
|
29
28
|
},
|
|
30
29
|
social: [],
|
|
31
30
|
|
|
31
|
+
lastUpdated: true,
|
|
32
|
+
|
|
32
33
|
license: {
|
|
33
34
|
enabled: true,
|
|
34
35
|
language: '',
|
|
@@ -96,9 +97,10 @@ const defaultValaxyConfig: ValaxyConfig = {
|
|
|
96
97
|
|
|
97
98
|
unocss: {},
|
|
98
99
|
|
|
99
|
-
markdown: {
|
|
100
|
-
|
|
101
|
-
},
|
|
100
|
+
// markdown: {
|
|
101
|
+
// excerpt: '<!-- more -->',
|
|
102
|
+
// },
|
|
103
|
+
|
|
102
104
|
markdownIt: {
|
|
103
105
|
toc: {
|
|
104
106
|
includeLevel: [1, 2, 3, 4],
|
|
@@ -152,19 +154,3 @@ export async function resolveConfig(options: ValaxyEntryOptions = {}) {
|
|
|
152
154
|
theme,
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Type config helper
|
|
158
|
-
*/
|
|
159
|
-
export function defineConfig(config: UserConfig<YunTheme.Config>) {
|
|
160
|
-
return config
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Type config helper for custom theme config
|
|
165
|
-
*/
|
|
166
|
-
export function defineConfigWithTheme<ThemeConfig>(
|
|
167
|
-
config: UserConfig<ThemeConfig>,
|
|
168
|
-
) {
|
|
169
|
-
return config
|
|
170
|
-
}
|
|
@@ -1,50 +1,38 @@
|
|
|
1
|
+
import { getHighlighter } from 'shiki'
|
|
1
2
|
import consola from 'consola'
|
|
2
|
-
import
|
|
3
|
-
import prism from 'prismjs'
|
|
3
|
+
import type { ThemeOptions } from '../markdown'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
5
|
+
export async function highlight(theme: ThemeOptions = 'material-palenight') {
|
|
6
|
+
const themes = typeof theme === 'string' ? [theme] : [theme.dark, theme.light]
|
|
7
|
+
const highlighter = await getHighlighter({ themes })
|
|
8
|
+
const preRE = /^<pre.*?>/
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
return (str: string, lang: string) => {
|
|
11
|
+
lang = lang || 'text'
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
code = escapeHtml(code)
|
|
13
|
+
// https://stackoverflow.com/questions/22268952/what-is-the-difference-between-yaml-and-yml-extension
|
|
14
|
+
// use yaml better
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return wrap(str, 'text')
|
|
22
|
-
|
|
23
|
-
lang = lang.toLowerCase()
|
|
24
|
-
const rawLang = lang
|
|
25
|
-
if (lang === 'vue' || lang === 'html')
|
|
26
|
-
lang = 'markup'
|
|
16
|
+
// adaptive
|
|
17
|
+
if (lang === 'yml') {
|
|
18
|
+
lang = 'yaml'
|
|
19
|
+
consola.warn('[shiki] It is recommended to use `.yaml` instead of `.yml`.')
|
|
20
|
+
}
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
if (typeof theme === 'string') {
|
|
23
|
+
return highlighter
|
|
24
|
+
.codeToHtml(str, { lang, theme })
|
|
25
|
+
.replace(preRE, '<pre v-pre>')
|
|
26
|
+
}
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const dark = highlighter
|
|
29
|
+
.codeToHtml(str, { lang, theme: theme.dark })
|
|
30
|
+
.replace(preRE, '<pre v-pre class="vp-code-dark">')
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const light = highlighter
|
|
33
|
+
.codeToHtml(str, { lang, theme: theme.light })
|
|
34
|
+
.replace(preRE, '<pre v-pre class="vp-code-light">')
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
loadLanguages([lang])
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
consola.warn(`[valaxy] Syntax highlight for language "${lang}" is not supported.`)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (prism.languages[lang]) {
|
|
46
|
-
const code = prism.highlight(str, prism.languages[lang], lang)
|
|
47
|
-
return wrap(code, rawLang)
|
|
36
|
+
return dark + light
|
|
48
37
|
}
|
|
49
|
-
return wrap(str, 'text')
|
|
50
38
|
}
|
package/node/markdown/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import MarkdownIt from 'markdown-it'
|
|
2
|
+
|
|
3
|
+
import type { Theme } from 'shiki'
|
|
2
4
|
|
|
3
5
|
import Anchor from 'markdown-it-anchor'
|
|
4
6
|
import Emoji from 'markdown-it-emoji'
|
|
@@ -8,23 +10,16 @@ import TaskLists from 'markdown-it-task-lists'
|
|
|
8
10
|
import attrs from 'markdown-it-attrs'
|
|
9
11
|
|
|
10
12
|
import type { KatexOptions } from 'katex'
|
|
13
|
+
import type { Header } from '../../types'
|
|
11
14
|
import Katex from './markdown-it/katex'
|
|
12
15
|
import { containerPlugin } from './markdown-it/container'
|
|
13
|
-
|
|
16
|
+
import { headingPlugin } from './markdown-it/headings'
|
|
14
17
|
import { slugify } from './slugify'
|
|
15
18
|
import { parseHeader } from './markdown-it/parseHeader'
|
|
16
19
|
import { highlight } from './highlight'
|
|
17
20
|
import { highlightLinePlugin, preWrapperPlugin } from './markdown-it/highlightLines'
|
|
18
21
|
|
|
19
|
-
export
|
|
20
|
-
level: number
|
|
21
|
-
title: string
|
|
22
|
-
slug: string
|
|
23
|
-
/**
|
|
24
|
-
* i18n
|
|
25
|
-
*/
|
|
26
|
-
lang?: string
|
|
27
|
-
}
|
|
22
|
+
export type ThemeOptions = Theme | { light: Theme; dark: Theme }
|
|
28
23
|
|
|
29
24
|
export interface MarkdownParsedData {
|
|
30
25
|
hoistedTags?: string[]
|
|
@@ -32,6 +27,8 @@ export interface MarkdownParsedData {
|
|
|
32
27
|
headers?: Header[]
|
|
33
28
|
}
|
|
34
29
|
export interface MarkdownRenderer extends MarkdownIt {
|
|
30
|
+
__path: string
|
|
31
|
+
__relativePath: string
|
|
35
32
|
__data: MarkdownParsedData
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -46,12 +43,13 @@ export interface MarkdownOptions extends MarkdownIt.Options {
|
|
|
46
43
|
[key: string]: any
|
|
47
44
|
}
|
|
48
45
|
katex?: KatexOptions
|
|
46
|
+
/**
|
|
47
|
+
* shiki
|
|
48
|
+
*/
|
|
49
|
+
theme?: ThemeOptions
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
|
|
52
|
-
md.set({
|
|
53
|
-
highlight,
|
|
54
|
-
})
|
|
52
|
+
export async function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}) {
|
|
55
53
|
md
|
|
56
54
|
.use(highlightLinePlugin)
|
|
57
55
|
.use(preWrapperPlugin)
|
|
@@ -59,7 +57,7 @@ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions
|
|
|
59
57
|
// conflict with {% %}
|
|
60
58
|
.use(attrs)
|
|
61
59
|
// generate toc in client
|
|
62
|
-
|
|
60
|
+
.use(headingPlugin, mdOptions?.toc?.includeLevel)
|
|
63
61
|
// .use(lineNumberPlugin)
|
|
64
62
|
// https://github.com/arve0/markdown-it-attrs
|
|
65
63
|
// add classes
|
|
@@ -93,3 +91,19 @@ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions
|
|
|
93
91
|
|
|
94
92
|
return md as MarkdownRenderer
|
|
95
93
|
}
|
|
94
|
+
|
|
95
|
+
export const createMarkdownRenderer = async (
|
|
96
|
+
srcDir: string,
|
|
97
|
+
options: MarkdownOptions = {},
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
|
+
base = '/',
|
|
100
|
+
): Promise<MarkdownRenderer> => {
|
|
101
|
+
const md = MarkdownIt({
|
|
102
|
+
html: true,
|
|
103
|
+
linkify: true,
|
|
104
|
+
highlight: await highlight(options.theme),
|
|
105
|
+
...options,
|
|
106
|
+
}) as MarkdownRenderer
|
|
107
|
+
await setupMarkdownPlugins(md)
|
|
108
|
+
return md
|
|
109
|
+
}
|
|
@@ -65,7 +65,7 @@ export const preWrapperPlugin = (md: MarkdownIt) => {
|
|
|
65
65
|
const [tokens, idx] = args
|
|
66
66
|
const token = tokens[idx]
|
|
67
67
|
const rawCode = fence(...args)
|
|
68
|
-
return `<div class="language-${token.info.trim()}">${rawCode}</div>`
|
|
68
|
+
return `<div class="language-${token.info.trim()}"><span class="copy"></span>${rawCode}</div>`
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// copy from vitepress
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import c from 'picocolors'
|
|
5
|
+
import matter from 'gray-matter'
|
|
6
|
+
import LRUCache from 'lru-cache'
|
|
7
|
+
import _debug from 'debug'
|
|
8
|
+
import { getGitTimestamp, slash, transformObject } from '../utils'
|
|
9
|
+
import { EXTERNAL_URL_RE } from '../../shared'
|
|
10
|
+
import type { HeadConfig, PageData } from '../../types'
|
|
11
|
+
import { deeplyParseHeader } from './markdown-it/parseHeader'
|
|
12
|
+
import { createMarkdownRenderer } from '.'
|
|
13
|
+
import type { MarkdownOptions } from '.'
|
|
14
|
+
|
|
15
|
+
const debug = _debug('vitepress:md')
|
|
16
|
+
const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 })
|
|
17
|
+
const includesRE = /<!--\s*@include:\s*(.*?)\s*-->/g
|
|
18
|
+
|
|
19
|
+
export interface MarkdownCompileResult {
|
|
20
|
+
vueSrc: string
|
|
21
|
+
pageData: PageData
|
|
22
|
+
deadLinks: string[]
|
|
23
|
+
includes: string[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const inferTitle = (frontmatter: Record<string, any>, content: string) => {
|
|
27
|
+
if (frontmatter.title)
|
|
28
|
+
return deeplyParseHeader(frontmatter.title)
|
|
29
|
+
|
|
30
|
+
const match = content.match(/^\s*#+\s+(.*)/m)
|
|
31
|
+
|
|
32
|
+
if (match)
|
|
33
|
+
return deeplyParseHeader(match[1].trim())
|
|
34
|
+
|
|
35
|
+
return ''
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const getHeadMetaContent = (
|
|
39
|
+
head: HeadConfig[],
|
|
40
|
+
name: string,
|
|
41
|
+
): string | undefined => {
|
|
42
|
+
if (!head || !head.length)
|
|
43
|
+
return undefined
|
|
44
|
+
|
|
45
|
+
const meta = head.find(([tag, attrs = {}]) => {
|
|
46
|
+
return tag === 'meta' && attrs.name === name && attrs.content
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return meta && meta[1].content
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const inferDescription = (frontmatter: Record<string, any>) => {
|
|
53
|
+
const { description, head } = frontmatter
|
|
54
|
+
|
|
55
|
+
if (description !== undefined)
|
|
56
|
+
return description
|
|
57
|
+
|
|
58
|
+
return (head && getHeadMetaContent(head, 'description')) || ''
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function createMarkdownToVueRenderFn(
|
|
62
|
+
srcDir: string,
|
|
63
|
+
options: MarkdownOptions = {},
|
|
64
|
+
pages: string[],
|
|
65
|
+
userDefines: Record<string, any> | undefined,
|
|
66
|
+
isBuild = false,
|
|
67
|
+
base = '/',
|
|
68
|
+
includeLastUpdatedData = false,
|
|
69
|
+
) {
|
|
70
|
+
const md = await createMarkdownRenderer(srcDir, options, base)
|
|
71
|
+
|
|
72
|
+
pages = pages.map(p => slash(p.replace(/\.md$/, '')))
|
|
73
|
+
|
|
74
|
+
const userDefineRegex = userDefines
|
|
75
|
+
? new RegExp(
|
|
76
|
+
`\\b(${Object.keys(userDefines)
|
|
77
|
+
.map(key => key.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'))
|
|
78
|
+
.join('|')})`,
|
|
79
|
+
'g',
|
|
80
|
+
)
|
|
81
|
+
: null
|
|
82
|
+
|
|
83
|
+
return async (
|
|
84
|
+
src: string,
|
|
85
|
+
file: string,
|
|
86
|
+
publicDir: string,
|
|
87
|
+
): Promise<MarkdownCompileResult> => {
|
|
88
|
+
const relativePath = slash(path.relative(srcDir, file))
|
|
89
|
+
const dir = path.dirname(file)
|
|
90
|
+
|
|
91
|
+
const cached = cache.get(src)
|
|
92
|
+
if (cached) {
|
|
93
|
+
debug(`[cache hit] ${relativePath}`)
|
|
94
|
+
return cached
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const start = Date.now()
|
|
98
|
+
|
|
99
|
+
// resolve includes
|
|
100
|
+
const includes: string[] = []
|
|
101
|
+
src = src.replace(includesRE, (_, m1) => {
|
|
102
|
+
const includePath = path.join(dir, m1)
|
|
103
|
+
const content = fs.readFileSync(includePath, 'utf-8')
|
|
104
|
+
includes.push(slash(includePath))
|
|
105
|
+
return content
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const { content, data: frontmatter } = matter(src)
|
|
109
|
+
|
|
110
|
+
// reset state before render
|
|
111
|
+
md.__path = file
|
|
112
|
+
md.__relativePath = relativePath
|
|
113
|
+
|
|
114
|
+
let html = md.render(content)
|
|
115
|
+
const data = md.__data
|
|
116
|
+
|
|
117
|
+
if (isBuild) {
|
|
118
|
+
// avoid env variables being replaced by vite
|
|
119
|
+
html = html
|
|
120
|
+
.replace(/\bimport\.meta/g, 'import.<wbr/>meta')
|
|
121
|
+
.replace(/\bprocess\.env/g, 'process.<wbr/>env')
|
|
122
|
+
|
|
123
|
+
// also avoid replacing vite user defines
|
|
124
|
+
if (userDefineRegex) {
|
|
125
|
+
html = html.replace(
|
|
126
|
+
userDefineRegex,
|
|
127
|
+
_ => `${_[0]}<wbr/>${_.slice(1)}`,
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// validate data.links
|
|
133
|
+
const deadLinks: string[] = []
|
|
134
|
+
const recordDeadLink = (url: string) => {
|
|
135
|
+
console.warn(
|
|
136
|
+
c.yellow(
|
|
137
|
+
`\n(!) Found dead link ${c.cyan(url)} in file ${c.white(c.dim(file))}`,
|
|
138
|
+
),
|
|
139
|
+
)
|
|
140
|
+
deadLinks.push(url)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (data.links) {
|
|
144
|
+
const dir = path.dirname(file)
|
|
145
|
+
for (let url of data.links) {
|
|
146
|
+
if (/\.(?!html|md)\w+($|\?)/i.test(url))
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
if (url.replace(EXTERNAL_URL_RE, '').startsWith('//localhost:')) {
|
|
150
|
+
recordDeadLink(url)
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
url = url.replace(/[?#].*$/, '').replace(/\.(html|md)$/, '')
|
|
155
|
+
if (url.endsWith('/'))
|
|
156
|
+
url += 'index'
|
|
157
|
+
const resolved = decodeURIComponent(
|
|
158
|
+
slash(
|
|
159
|
+
url.startsWith('/')
|
|
160
|
+
? url.slice(1)
|
|
161
|
+
: path.relative(srcDir, path.resolve(dir, url)),
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
if (
|
|
165
|
+
!pages.includes(resolved)
|
|
166
|
+
&& !fs.existsSync(path.resolve(dir, publicDir, `${resolved}.html`))
|
|
167
|
+
)
|
|
168
|
+
recordDeadLink(url)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const pageData: PageData = {
|
|
173
|
+
title: inferTitle(frontmatter, content),
|
|
174
|
+
titleTemplate: frontmatter.titleTemplate,
|
|
175
|
+
description: inferDescription(frontmatter),
|
|
176
|
+
frontmatter,
|
|
177
|
+
headers: data.headers || [],
|
|
178
|
+
relativePath,
|
|
179
|
+
path: path.join(srcDir, relativePath),
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (includeLastUpdatedData)
|
|
183
|
+
pageData.lastUpdated = await getGitTimestamp(file)
|
|
184
|
+
|
|
185
|
+
const pageComponent = 'ValaxyMain'
|
|
186
|
+
|
|
187
|
+
function generateSlots() {
|
|
188
|
+
const slots = [
|
|
189
|
+
'main-header',
|
|
190
|
+
'main-header-after',
|
|
191
|
+
'main-nav',
|
|
192
|
+
'main-content',
|
|
193
|
+
'main-content-after',
|
|
194
|
+
'footer',
|
|
195
|
+
'aside',
|
|
196
|
+
'aside-custom',
|
|
197
|
+
]
|
|
198
|
+
const slotsText = slots.map(s => `<template #${s}><slot name="${s}" /></template>`).join('')
|
|
199
|
+
return slotsText
|
|
200
|
+
}
|
|
201
|
+
const vueSrc
|
|
202
|
+
= `${genPageDataCode(data.hoistedTags || [], pageData).join('\n')
|
|
203
|
+
}\n<template><${pageComponent} :frontmatter="frontmatter" :data="data">
|
|
204
|
+
<template #main-content-md>${html}</template>
|
|
205
|
+
${generateSlots()}
|
|
206
|
+
<slot />
|
|
207
|
+
</${pageComponent}></template>`
|
|
208
|
+
|
|
209
|
+
debug(`[render] ${file} in ${Date.now() - start}ms.`)
|
|
210
|
+
|
|
211
|
+
const result = {
|
|
212
|
+
vueSrc,
|
|
213
|
+
pageData,
|
|
214
|
+
deadLinks,
|
|
215
|
+
includes,
|
|
216
|
+
}
|
|
217
|
+
cache.set(src, result)
|
|
218
|
+
return result
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const scriptRE = /<\/script>/
|
|
223
|
+
const scriptLangTsRE = /<\s*script[^>]*\blang=['"]ts['"][^>]*/
|
|
224
|
+
const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/
|
|
225
|
+
const scriptClientRE = /<\s*script[^>]*\bclient\b[^>]*/
|
|
226
|
+
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
|
|
227
|
+
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/
|
|
228
|
+
|
|
229
|
+
function genPageDataCode(tags: string[], data: PageData) {
|
|
230
|
+
const code = ''
|
|
231
|
+
|
|
232
|
+
const existingScriptIndex = tags.findIndex((tag) => {
|
|
233
|
+
return (
|
|
234
|
+
scriptRE.test(tag)
|
|
235
|
+
&& !scriptSetupRE.test(tag)
|
|
236
|
+
&& !scriptClientRE.test(tag)
|
|
237
|
+
)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const isUsingTS = tags.findIndex(tag => scriptLangTsRE.test(tag)) > -1
|
|
241
|
+
|
|
242
|
+
const exportScript = `
|
|
243
|
+
export default {
|
|
244
|
+
name:'${data.relativePath}',
|
|
245
|
+
data() {
|
|
246
|
+
return {
|
|
247
|
+
frontmatter:${transformObject(data.frontmatter)},
|
|
248
|
+
data: ${transformObject(data)}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}`
|
|
252
|
+
|
|
253
|
+
if (existingScriptIndex > -1) {
|
|
254
|
+
const tagSrc = tags[existingScriptIndex]
|
|
255
|
+
// user has <script> tag inside markdown
|
|
256
|
+
// if it doesn't have export default it will error out on build
|
|
257
|
+
const hasDefaultExport
|
|
258
|
+
= defaultExportRE.test(tagSrc) || namedDefaultExportRE.test(tagSrc)
|
|
259
|
+
tags[existingScriptIndex] = tagSrc.replace(
|
|
260
|
+
scriptRE,
|
|
261
|
+
`${code
|
|
262
|
+
+ (hasDefaultExport
|
|
263
|
+
? ''
|
|
264
|
+
: `\n${exportScript}`)
|
|
265
|
+
}</script>`,
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
tags.unshift(
|
|
270
|
+
`<script ${isUsingTS ? 'lang="ts"' : ''}>${code}\n${exportScript}</script>`,
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return tags
|
|
275
|
+
}
|
package/node/options.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dirname, resolve } from 'path'
|
|
2
2
|
import _debug from 'debug'
|
|
3
|
+
import fg from 'fast-glob'
|
|
3
4
|
import type { ValaxyConfig } from '../types'
|
|
4
5
|
import { resolveConfig } from './config'
|
|
5
6
|
import { resolveImportPath } from './utils'
|
|
@@ -43,6 +44,7 @@ export interface ResolvedValaxyOptions {
|
|
|
43
44
|
* config file path
|
|
44
45
|
*/
|
|
45
46
|
configFile: string
|
|
47
|
+
pages: string[]
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
export interface ValaxyServerOptions {
|
|
@@ -77,6 +79,19 @@ export async function resolveOptions(options: ValaxyEntryOptions, mode: Resolved
|
|
|
77
79
|
const { config: valaxyConfig, configFile, theme } = await resolveConfig(options)
|
|
78
80
|
const themeRoot = getThemeRoot(theme, userRoot)
|
|
79
81
|
|
|
82
|
+
// Important: fast-glob doesn't guarantee order of the returned files.
|
|
83
|
+
// We must sort the pages so the input list to rollup is stable across
|
|
84
|
+
// builds - otherwise different input order could result in different exports
|
|
85
|
+
// order in shared chunks which in turns invalidates the hash of every chunk!
|
|
86
|
+
// JavaScript built-in sort() is mandated to be stable as of ES2019 and
|
|
87
|
+
// supported in Node 12+, which is required by Vite.
|
|
88
|
+
const pages = (
|
|
89
|
+
await fg(['**.md'], {
|
|
90
|
+
cwd: userRoot,
|
|
91
|
+
ignore: ['**/node_modules'],
|
|
92
|
+
})
|
|
93
|
+
).sort()
|
|
94
|
+
|
|
80
95
|
const valaxyOptions: ResolvedValaxyOptions = {
|
|
81
96
|
mode,
|
|
82
97
|
clientRoot,
|
|
@@ -85,6 +100,7 @@ export async function resolveOptions(options: ValaxyEntryOptions, mode: Resolved
|
|
|
85
100
|
theme,
|
|
86
101
|
config: valaxyConfig,
|
|
87
102
|
configFile: configFile || '',
|
|
103
|
+
pages,
|
|
88
104
|
}
|
|
89
105
|
debug(valaxyOptions)
|
|
90
106
|
|
|
@@ -14,13 +14,13 @@ export function createConfigPlugin(options: ResolvedValaxyOptions): Plugin {
|
|
|
14
14
|
'@/': `${toAtFS(options.userRoot)}/`,
|
|
15
15
|
'~/': `${toAtFS(options.clientRoot)}/`,
|
|
16
16
|
'valaxy/client': `${toAtFS(options.clientRoot)}/`,
|
|
17
|
+
'valaxy': toAtFS(resolve(options.clientRoot, 'index.ts')),
|
|
17
18
|
'@valaxyjs/client': `${toAtFS(options.clientRoot)}/`,
|
|
18
19
|
'@valaxyjs/config': '/@valaxyjs/config',
|
|
20
|
+
'@valaxyjs/context': '/@valaxyjs/context',
|
|
19
21
|
'valaxy/package.json': toAtFS(resolve(options.clientRoot, '../../package.json')),
|
|
20
|
-
'valaxy/': `${toAtFS(resolve(options.clientRoot, '..'))}/`,
|
|
21
|
-
'valaxy': toAtFS(resolve(options.clientRoot, '../index.ts')),
|
|
22
22
|
[`valaxy-theme-${options.theme}/`]: `${toAtFS(resolve(options.themeRoot))}/`,
|
|
23
|
-
[`valaxy-theme-${options.theme}`]: `${toAtFS(resolve(options.themeRoot))}`,
|
|
23
|
+
[`valaxy-theme-${options.theme}`]: `${toAtFS(resolve(options.themeRoot))}/index.ts`,
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
|
|
@@ -37,6 +37,7 @@ export function createConfigPlugin(options: ResolvedValaxyOptions): Plugin {
|
|
|
37
37
|
'nprogress',
|
|
38
38
|
],
|
|
39
39
|
|
|
40
|
+
exclude: ['@docsearch/js'],
|
|
40
41
|
},
|
|
41
42
|
}
|
|
42
43
|
return mergeConfig(config, injection)
|