valaxy 0.5.0 → 0.6.0
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/ValaxyToc.vue +3 -3
- package/client/composables/outline.ts +181 -0
- package/client/composables/sidebar.ts +58 -1
- package/client/config.ts +30 -7
- package/client/main.ts +4 -1
- package/client/modules/valaxy.ts +33 -8
- package/client/shims.d.ts +6 -1
- package/client/styles/palette.scss +6 -2
- package/client/utils/helper.ts +22 -0
- package/client/utils/sidebar.ts +26 -0
- package/config/index.ts +18 -0
- package/dist/chunk-CP3UCJ2D.js +34 -0
- package/dist/chunk-HCVZ2UUO.mjs +34 -0
- package/dist/{config-7bd43d41.d.ts → config-ad23e743.d.ts} +6 -4
- package/dist/index.d.ts +363 -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 +2 -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/index.ts +21 -13
- package/node/markdown/markdownToVue.ts +253 -0
- package/node/options.ts +16 -0
- package/node/plugins/extendConfig.ts +4 -3
- package/node/plugins/index.ts +103 -6
- package/node/plugins/preset.ts +6 -6
- package/node/rss.ts +1 -1
- package/node/utils/getGitTimestamp.ts +13 -0
- package/node/utils/index.ts +11 -0
- package/package.json +20 -7
- 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,9 +1,8 @@
|
|
|
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-ad23e743.js';
|
|
4
4
|
import 'type-fest';
|
|
5
5
|
import 'unocss/vite';
|
|
6
|
-
import 'vite-plugin-md';
|
|
7
6
|
import 'markdown-it';
|
|
8
7
|
import 'markdown-it-anchor';
|
|
9
8
|
import 'katex';
|
|
@@ -36,6 +35,7 @@ interface ResolvedValaxyOptions {
|
|
|
36
35
|
* config file path
|
|
37
36
|
*/
|
|
38
37
|
configFile: string;
|
|
38
|
+
pages: string[];
|
|
39
39
|
}
|
|
40
40
|
interface ValaxyServerOptions {
|
|
41
41
|
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 _chunkCP3UCJ2Djs = require('../chunk-CP3UCJ2D.js');require('../chunk-U5OMNIOK.js');exports.createServer = _chunkCP3UCJ2Djs.f;
|
package/dist/node/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{f as o}from"../chunk-HCVZ2UUO.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
|
-
}
|
package/node/markdown/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import MarkdownIt from 'markdown-it'
|
|
2
2
|
|
|
3
3
|
import Anchor from 'markdown-it-anchor'
|
|
4
4
|
import Emoji from 'markdown-it-emoji'
|
|
@@ -8,30 +8,23 @@ import TaskLists from 'markdown-it-task-lists'
|
|
|
8
8
|
import attrs from 'markdown-it-attrs'
|
|
9
9
|
|
|
10
10
|
import type { KatexOptions } from 'katex'
|
|
11
|
+
import type { Header } from '../../types'
|
|
11
12
|
import Katex from './markdown-it/katex'
|
|
12
13
|
import { containerPlugin } from './markdown-it/container'
|
|
13
|
-
|
|
14
|
+
import { headingPlugin } from './markdown-it/headings'
|
|
14
15
|
import { slugify } from './slugify'
|
|
15
16
|
import { parseHeader } from './markdown-it/parseHeader'
|
|
16
17
|
import { highlight } from './highlight'
|
|
17
18
|
import { highlightLinePlugin, preWrapperPlugin } from './markdown-it/highlightLines'
|
|
18
19
|
|
|
19
|
-
export interface Header {
|
|
20
|
-
level: number
|
|
21
|
-
title: string
|
|
22
|
-
slug: string
|
|
23
|
-
/**
|
|
24
|
-
* i18n
|
|
25
|
-
*/
|
|
26
|
-
lang?: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
20
|
export interface MarkdownParsedData {
|
|
30
21
|
hoistedTags?: string[]
|
|
31
22
|
links?: string[]
|
|
32
23
|
headers?: Header[]
|
|
33
24
|
}
|
|
34
25
|
export interface MarkdownRenderer extends MarkdownIt {
|
|
26
|
+
__path: string
|
|
27
|
+
__relativePath: string
|
|
35
28
|
__data: MarkdownParsedData
|
|
36
29
|
}
|
|
37
30
|
|
|
@@ -59,7 +52,7 @@ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions
|
|
|
59
52
|
// conflict with {% %}
|
|
60
53
|
.use(attrs)
|
|
61
54
|
// generate toc in client
|
|
62
|
-
|
|
55
|
+
.use(headingPlugin, mdOptions?.toc?.includeLevel)
|
|
63
56
|
// .use(lineNumberPlugin)
|
|
64
57
|
// https://github.com/arve0/markdown-it-attrs
|
|
65
58
|
// add classes
|
|
@@ -93,3 +86,18 @@ export function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions
|
|
|
93
86
|
|
|
94
87
|
return md as MarkdownRenderer
|
|
95
88
|
}
|
|
89
|
+
|
|
90
|
+
export const createMarkdownRenderer = async (
|
|
91
|
+
srcDir: string,
|
|
92
|
+
options: MarkdownOptions = {},
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
94
|
+
base = '/',
|
|
95
|
+
): Promise<MarkdownRenderer> => {
|
|
96
|
+
const md = MarkdownIt({
|
|
97
|
+
html: true,
|
|
98
|
+
linkify: true,
|
|
99
|
+
...options,
|
|
100
|
+
}) as MarkdownRenderer
|
|
101
|
+
setupMarkdownPlugins(md)
|
|
102
|
+
return md
|
|
103
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
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 valaxyMd = 'ValaxyMd'
|
|
186
|
+
const vueSrc
|
|
187
|
+
= `${genPageDataCode(data.hoistedTags || [], pageData).join('\n')
|
|
188
|
+
}\n<template><${valaxyMd} :frontmatter="frontmatter">${html}</${valaxyMd}></template>`
|
|
189
|
+
|
|
190
|
+
debug(`[render] ${file} in ${Date.now() - start}ms.`)
|
|
191
|
+
|
|
192
|
+
const result = {
|
|
193
|
+
vueSrc,
|
|
194
|
+
pageData,
|
|
195
|
+
deadLinks,
|
|
196
|
+
includes,
|
|
197
|
+
}
|
|
198
|
+
cache.set(src, result)
|
|
199
|
+
return result
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const scriptRE = /<\/script>/
|
|
204
|
+
const scriptLangTsRE = /<\s*script[^>]*\blang=['"]ts['"][^>]*/
|
|
205
|
+
const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/
|
|
206
|
+
const scriptClientRE = /<\s*script[^>]*\bclient\b[^>]*/
|
|
207
|
+
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
|
|
208
|
+
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/
|
|
209
|
+
|
|
210
|
+
function genPageDataCode(tags: string[], data: PageData) {
|
|
211
|
+
const code = `\nexport const __pageData = ${transformObject(data)}`
|
|
212
|
+
|
|
213
|
+
const existingScriptIndex = tags.findIndex((tag) => {
|
|
214
|
+
return (
|
|
215
|
+
scriptRE.test(tag)
|
|
216
|
+
&& !scriptSetupRE.test(tag)
|
|
217
|
+
&& !scriptClientRE.test(tag)
|
|
218
|
+
)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const isUsingTS = tags.findIndex(tag => scriptLangTsRE.test(tag)) > -1
|
|
222
|
+
|
|
223
|
+
const exportScript = `
|
|
224
|
+
export default {
|
|
225
|
+
name:'${data.relativePath}',
|
|
226
|
+
data() {
|
|
227
|
+
return {frontmatter:${transformObject(data.frontmatter)}}
|
|
228
|
+
}
|
|
229
|
+
}`
|
|
230
|
+
|
|
231
|
+
if (existingScriptIndex > -1) {
|
|
232
|
+
const tagSrc = tags[existingScriptIndex]
|
|
233
|
+
// user has <script> tag inside markdown
|
|
234
|
+
// if it doesn't have export default it will error out on build
|
|
235
|
+
const hasDefaultExport
|
|
236
|
+
= defaultExportRE.test(tagSrc) || namedDefaultExportRE.test(tagSrc)
|
|
237
|
+
tags[existingScriptIndex] = tagSrc.replace(
|
|
238
|
+
scriptRE,
|
|
239
|
+
`${code
|
|
240
|
+
+ (hasDefaultExport
|
|
241
|
+
? ''
|
|
242
|
+
: `\n${exportScript}`)
|
|
243
|
+
}</script>`,
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
tags.unshift(
|
|
248
|
+
`<script ${isUsingTS ? 'lang="ts"' : ''}>${code}\n${exportScript}</script>`,
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return tags
|
|
253
|
+
}
|
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)
|
package/node/plugins/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
2
|
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import type { Plugin } from 'vite'
|
|
3
|
+
import { join, relative } from 'path'
|
|
4
|
+
import type { Plugin, ResolvedConfig } from 'vite'
|
|
5
5
|
// import consola from 'consola'
|
|
6
6
|
import { resolveConfig } from '../config'
|
|
7
7
|
import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
|
|
8
|
-
import { resolveImportPath, toAtFS } from '../utils'
|
|
8
|
+
import { resolveImportPath, slash, toAtFS } from '../utils'
|
|
9
|
+
import { createMarkdownToVueRenderFn } from '../markdown/markdownToVue'
|
|
10
|
+
import type { PageDataPayload } from '../../types'
|
|
11
|
+
import { checkMd } from '../markdown/check'
|
|
9
12
|
import { VALAXY_CONFIG_ID } from './valaxy'
|
|
10
13
|
|
|
11
14
|
/**
|
|
@@ -68,8 +71,26 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
|
|
|
68
71
|
|
|
69
72
|
const roots = [options.clientRoot, options.themeRoot, options.userRoot]
|
|
70
73
|
|
|
74
|
+
let markdownToVue: Awaited<ReturnType<typeof createMarkdownToVueRenderFn>>
|
|
75
|
+
let hasDeadLinks = false
|
|
76
|
+
let config: ResolvedConfig
|
|
77
|
+
|
|
71
78
|
return {
|
|
72
|
-
name: '
|
|
79
|
+
name: 'valaxy',
|
|
80
|
+
enforce: 'pre',
|
|
81
|
+
|
|
82
|
+
async configResolved(resolvedConfig) {
|
|
83
|
+
config = resolvedConfig
|
|
84
|
+
markdownToVue = await createMarkdownToVueRenderFn(
|
|
85
|
+
options.userRoot,
|
|
86
|
+
options.config.markdownIt,
|
|
87
|
+
options.pages,
|
|
88
|
+
config.define,
|
|
89
|
+
config.command === 'build',
|
|
90
|
+
config.base,
|
|
91
|
+
options.config.lastUpdated,
|
|
92
|
+
)
|
|
93
|
+
},
|
|
73
94
|
|
|
74
95
|
configureServer(server) {
|
|
75
96
|
server.watcher.add([
|
|
@@ -90,6 +111,13 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
|
|
|
90
111
|
// stringify twice for \"
|
|
91
112
|
return `export default ${JSON.stringify(JSON.stringify(valaxyConfig))}`
|
|
92
113
|
|
|
114
|
+
if (id === '/@valaxyjs/context') {
|
|
115
|
+
return `export default ${JSON.stringify(JSON.stringify({
|
|
116
|
+
userRoot: options.userRoot,
|
|
117
|
+
// clientRoot: options.clientRoot,
|
|
118
|
+
}))}`
|
|
119
|
+
}
|
|
120
|
+
|
|
93
121
|
// generate styles
|
|
94
122
|
if (id === '/@valaxyjs/styles')
|
|
95
123
|
return generateStyles(roots, options)
|
|
@@ -101,12 +129,81 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
|
|
|
101
129
|
return ''
|
|
102
130
|
},
|
|
103
131
|
|
|
132
|
+
async transform(code, id) {
|
|
133
|
+
if (id.endsWith('.md')) {
|
|
134
|
+
checkMd(code, id)
|
|
135
|
+
code.replace('{%', '\{\%')
|
|
136
|
+
code.replace('%}', '\%\}')
|
|
137
|
+
|
|
138
|
+
// const scripts = [
|
|
139
|
+
// '<script setup>',
|
|
140
|
+
// 'import { useRoute } from "vue-router"',
|
|
141
|
+
// 'const route = useRoute()',
|
|
142
|
+
// `route.meta.headers = ${JSON.stringify(_md.__data)}`,
|
|
143
|
+
// `export const data = JSON.parse(${JSON.stringify(JSON.stringify(pageData))})`,
|
|
144
|
+
// `frontmatter.data = JSON.parse(${JSON.stringify(JSON.stringify(pageData))})`,
|
|
145
|
+
// '</script>',
|
|
146
|
+
// ]
|
|
147
|
+
|
|
148
|
+
// const li = code.lastIndexOf('</script>')
|
|
149
|
+
// code = code.slice(0, li) + scripts.join('\n') + code.slice(li + 9)
|
|
150
|
+
|
|
151
|
+
// transform .md files into vueSrc so plugin-vue can handle it
|
|
152
|
+
const { vueSrc, deadLinks, includes } = await markdownToVue(
|
|
153
|
+
code,
|
|
154
|
+
id,
|
|
155
|
+
config.publicDir,
|
|
156
|
+
)
|
|
157
|
+
if (deadLinks.length)
|
|
158
|
+
hasDeadLinks = true
|
|
159
|
+
|
|
160
|
+
if (includes.length) {
|
|
161
|
+
includes.forEach((i) => {
|
|
162
|
+
this.addWatchFile(i)
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return vueSrc
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
renderStart() {
|
|
171
|
+
if (hasDeadLinks)
|
|
172
|
+
throw new Error('One or more pages contain dead links.')
|
|
173
|
+
},
|
|
174
|
+
|
|
104
175
|
async handleHotUpdate(ctx) {
|
|
105
176
|
// handle valaxy.config.ts hmr
|
|
106
|
-
const { file, server } = ctx
|
|
177
|
+
const { file, server, read } = ctx
|
|
107
178
|
if (file !== options.configFile)
|
|
108
179
|
return
|
|
109
180
|
|
|
181
|
+
// send headers
|
|
182
|
+
if (file.endsWith('.md')) {
|
|
183
|
+
const content = await read()
|
|
184
|
+
const { pageData, vueSrc } = await markdownToVue(
|
|
185
|
+
content,
|
|
186
|
+
file,
|
|
187
|
+
join(options.userRoot, 'public'),
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
const path = `/${slash(relative(`${options.userRoot}/pages`, file))}`
|
|
191
|
+
const payload: PageDataPayload = {
|
|
192
|
+
// path: `/${slash(relative(srcDir, file))}`,
|
|
193
|
+
path,
|
|
194
|
+
pageData,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
server.ws.send({
|
|
198
|
+
type: 'custom',
|
|
199
|
+
event: 'valaxy:pageData',
|
|
200
|
+
data: payload,
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// overwrite src so vue plugin can handle the HMR
|
|
204
|
+
ctx.read = () => vueSrc
|
|
205
|
+
}
|
|
206
|
+
|
|
110
207
|
const { config } = await resolveConfig()
|
|
111
208
|
|
|
112
209
|
serverOptions.onConfigReload?.(config, options.config)
|
|
@@ -116,7 +213,7 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
|
|
|
116
213
|
// consola.warn('[valaxy]: config.base has changed. Please restart the dev server.')
|
|
117
214
|
valaxyConfig = config
|
|
118
215
|
|
|
119
|
-
const moduleIds = [`/${VALAXY_CONFIG_ID}
|
|
216
|
+
const moduleIds = [`/${VALAXY_CONFIG_ID}`, '/@valaxyjs/context']
|
|
120
217
|
const moduleEntries = [
|
|
121
218
|
...Array.from(moduleIds).map(id => server.moduleGraph.getModuleById(id)),
|
|
122
219
|
].filter(<T>(item: T): item is NonNullable<T> => !!item)
|
package/node/plugins/preset.ts
CHANGED
|
@@ -16,7 +16,7 @@ import Inspect from 'vite-plugin-inspect'
|
|
|
16
16
|
import { dim, yellow } from 'kolorist'
|
|
17
17
|
import type { ResolvedValaxyOptions, ValaxyServerOptions } from '../options'
|
|
18
18
|
import { setupMarkdownPlugins } from '../markdown'
|
|
19
|
-
import { createMarkdownPlugin, excerpt_separator } from './markdown'
|
|
19
|
+
// import { createMarkdownPlugin, excerpt_separator } from './markdown'
|
|
20
20
|
import { createUnocssPlugin } from './unocss'
|
|
21
21
|
import { createConfigPlugin } from './extendConfig'
|
|
22
22
|
import { createValaxyPlugin } from '.'
|
|
@@ -32,7 +32,7 @@ export async function ViteValaxyPlugins(
|
|
|
32
32
|
): Promise<(PluginOption | PluginOption[])[] | undefined> {
|
|
33
33
|
const { clientRoot, themeRoot, userRoot } = options
|
|
34
34
|
|
|
35
|
-
const MarkdownPlugin = createMarkdownPlugin(options)
|
|
35
|
+
// const MarkdownPlugin = createMarkdownPlugin(options)
|
|
36
36
|
const UnocssPlugin = await createUnocssPlugin(options)
|
|
37
37
|
|
|
38
38
|
const ValaxyPlugin = createValaxyPlugin(options, serverOptions)
|
|
@@ -42,7 +42,7 @@ export async function ViteValaxyPlugins(
|
|
|
42
42
|
|
|
43
43
|
const roots = [clientRoot, themeRoot, userRoot]
|
|
44
44
|
|
|
45
|
-
const { default: ThemePlugin } = await import(`valaxy-theme-${options.theme}`)
|
|
45
|
+
const { default: ThemePlugin } = (await import(`valaxy-theme-${options.theme}`))
|
|
46
46
|
|
|
47
47
|
const customElements = new Set([
|
|
48
48
|
// katex
|
|
@@ -90,8 +90,8 @@ export async function ViteValaxyPlugins(
|
|
|
90
90
|
},
|
|
91
91
|
}),
|
|
92
92
|
|
|
93
|
-
ValaxyPlugin,
|
|
94
93
|
createConfigPlugin(options),
|
|
94
|
+
ValaxyPlugin,
|
|
95
95
|
|
|
96
96
|
ThemePlugin(options.config.themeConfig),
|
|
97
97
|
|
|
@@ -118,7 +118,7 @@ export async function ViteValaxyPlugins(
|
|
|
118
118
|
})
|
|
119
119
|
|
|
120
120
|
const md = fs.readFileSync(path, 'utf-8')
|
|
121
|
-
const { data, excerpt } = matter(md, { excerpt_separator })
|
|
121
|
+
const { data, excerpt } = matter(md, { excerpt_separator: '<!-- more -->' })
|
|
122
122
|
|
|
123
123
|
// warn for post frontmatter
|
|
124
124
|
if (route.path.startsWith('/posts/')) {
|
|
@@ -170,7 +170,7 @@ export async function ViteValaxyPlugins(
|
|
|
170
170
|
// UnocssPlugin,
|
|
171
171
|
UnocssPlugin,
|
|
172
172
|
|
|
173
|
-
...MarkdownPlugin,
|
|
173
|
+
// ...MarkdownPlugin,
|
|
174
174
|
|
|
175
175
|
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
|
|
176
176
|
VueI18n({
|