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.
Files changed (55) hide show
  1. package/README.md +0 -4
  2. package/{dist/types/index.mjs → client/app/data.ts} +0 -0
  3. package/client/components/PostCard.vue +4 -2
  4. package/client/components/ValaxyBg.vue +1 -1
  5. package/client/components/ValaxyFooter.vue +1 -1
  6. package/client/components/ValaxyToc.vue +3 -3
  7. package/client/composables/outline.ts +181 -0
  8. package/client/composables/sidebar.ts +58 -1
  9. package/client/config.ts +30 -7
  10. package/client/main.ts +4 -1
  11. package/client/modules/valaxy.ts +33 -8
  12. package/client/shims.d.ts +6 -1
  13. package/client/styles/palette.scss +6 -2
  14. package/client/utils/helper.ts +22 -0
  15. package/client/utils/sidebar.ts +26 -0
  16. package/config/index.ts +18 -0
  17. package/dist/chunk-CP3UCJ2D.js +34 -0
  18. package/dist/chunk-HCVZ2UUO.mjs +34 -0
  19. package/dist/{config-7bd43d41.d.ts → config-ad23e743.d.ts} +6 -4
  20. package/dist/index.d.ts +363 -0
  21. package/dist/index.js +1 -0
  22. package/dist/index.mjs +1 -0
  23. package/dist/node/cli.js +7 -11
  24. package/dist/node/cli.mjs +7 -11
  25. package/dist/node/index.d.ts +2 -2
  26. package/dist/node/index.js +1 -1
  27. package/dist/node/index.mjs +1 -1
  28. package/index.ts +3 -0
  29. package/node/config.ts +9 -23
  30. package/node/markdown/index.ts +21 -13
  31. package/node/markdown/markdownToVue.ts +253 -0
  32. package/node/options.ts +16 -0
  33. package/node/plugins/extendConfig.ts +4 -3
  34. package/node/plugins/index.ts +103 -6
  35. package/node/plugins/preset.ts +6 -6
  36. package/node/rss.ts +1 -1
  37. package/node/utils/getGitTimestamp.ts +13 -0
  38. package/node/utils/index.ts +11 -0
  39. package/package.json +20 -7
  40. package/shared/index.ts +1 -0
  41. package/tsup.config.ts +5 -3
  42. package/types/config.ts +7 -4
  43. package/types/data.ts +31 -0
  44. package/types/index.ts +1 -0
  45. package/types/posts.ts +1 -1
  46. package/dist/chunk-RSQONJW3.mjs +0 -86
  47. package/dist/chunk-XQIGHIAX.js +0 -86
  48. package/dist/client/index.d.ts +0 -188
  49. package/dist/client/index.js +0 -1
  50. package/dist/client/index.mjs +0 -1
  51. package/dist/posts-32f55e33.d.ts +0 -117
  52. package/dist/types/index.d.ts +0 -8
  53. package/dist/types/index.js +0 -1
  54. package/index.d.ts +0 -3
  55. package/node/plugins/markdown.ts +0 -54
@@ -1,9 +1,8 @@
1
1
  import * as vite from 'vite';
2
2
  import { InlineConfig } from 'vite';
3
- import { V as ValaxyConfig } from '../config-7bd43d41.js';
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;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkXQIGHIAXjs = require('../chunk-XQIGHIAX.js');require('../chunk-U5OMNIOK.js');exports.createServer = _chunkXQIGHIAXjs.g;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkCP3UCJ2Djs = require('../chunk-CP3UCJ2D.js');require('../chunk-U5OMNIOK.js');exports.createServer = _chunkCP3UCJ2Djs.f;
@@ -1 +1 @@
1
- import{g as o}from"../chunk-RSQONJW3.mjs";import"../chunk-EAN2KU6W.mjs";export{o as createServer};
1
+ import{f as o}from"../chunk-HCVZ2UUO.mjs";import"../chunk-EAN2KU6W.mjs";export{o as createServer};
package/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './client'
2
+ export * from './types'
3
+ export * from './config'
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 { YunTheme } from 'valaxy-theme-yun'
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
- excerpt: '<!-- more -->',
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,4 +1,4 @@
1
- import type MarkdownIt from 'markdown-it'
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
- // import { headingPlugin } from './markdown-it/headings'
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
- // .use(headingPlugin, mdOptions?.toc?.includeLevel)
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)
@@ -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: 'Valaxy',
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)
@@ -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({