Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b4ff6a7
refactor: remove temp page files and load page component via bundler
meteorlxy Sep 10, 2024
d47d573
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 10, 2024
e681fb3
refactor: updates
meteorlxy Sep 11, 2024
e7b4e27
chore: tweaks
meteorlxy Sep 11, 2024
3bb73dc
refactor: improve hmr code injection
meteorlxy Sep 11, 2024
cb80a9e
chore: fix params
meteorlxy Sep 11, 2024
5f156ae
refactor: normalize module config
meteorlxy Sep 11, 2024
e597cab
test: fix unit tests
meteorlxy Sep 11, 2024
0e85a00
chore: revert page type update
meteorlxy Sep 11, 2024
4e0c08f
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 11, 2024
3f63c9e
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 11, 2024
9683840
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 11, 2024
3cfbb6f
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 11, 2024
d45c678
feat: inject default export
meteorlxy Sep 11, 2024
e4211ba
chore: tweaks
meteorlxy Sep 11, 2024
e8e0f51
Merge branch 'main' into meteorlxy-markdown-to-vue
Mister-Hope Sep 11, 2024
5989c91
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 12, 2024
a0da533
refactor(core): improve comments
meteorlxy Sep 12, 2024
6d156a0
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 12, 2024
b091364
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Sep 12, 2024
73ae7fc
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Oct 1, 2024
2d5e934
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Oct 10, 2024
2227b2b
Merge branch 'main' into meteorlxy-markdown-to-vue
Mister-Hope Feb 21, 2025
b92e3d1
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Feb 23, 2025
4e4bc0b
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Feb 25, 2025
7613c25
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Mar 3, 2025
a3032c5
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Apr 10, 2025
bbca706
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Apr 14, 2025
80ef3c7
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Apr 22, 2025
798741b
Merge branch 'main' into meteorlxy-markdown-to-vue
meteorlxy Aug 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor: remove temp page files and load page component via bundler
  • Loading branch information
meteorlxy committed Sep 10, 2024
commit b4ff6a74f3de3c50cc9823d0d47c1f0d80448a5f
5 changes: 0 additions & 5 deletions e2e/docs/.vuepress/components/ComponentForMarkdownImport.vue

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div class="component-for-markdown-import-bar">
<p>component for markdown import bar</p>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div class="component-for-markdown-import-foo">
<p>component for markdown import foo</p>
</div>
</template>
5 changes: 5 additions & 0 deletions e2e/docs/.vuepress/markdowns/dangling-markdown-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="dangling-markdown-file">

dangling markdown file

</div>
2 changes: 2 additions & 0 deletions e2e/docs/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
foo

## Home H2

demo
11 changes: 8 additions & 3 deletions e2e/docs/markdown/vue-components.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<ComponentForMarkdownGlobal />

<ComponentForMarkdownImport />
<ComponentForMarkdownImportFoo />

<ComponentForMarkdownImportBar />

<script setup>
// TODO: relative path import?
import ComponentForMarkdownImport from '@source/.vuepress/components/ComponentForMarkdownImport.vue';
// import via alias
import ComponentForMarkdownImportFoo from '@source/.vuepress/components/ComponentForMarkdownImportFoo.vue';

// import via relative path
import ComponentForMarkdownImportBar from '../.vuepress/components/ComponentForMarkdownImportBar.vue';
</script>
7 changes: 5 additions & 2 deletions e2e/tests/markdown/vue-components.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ test('should render vue components correctly', async ({ page }) => {
await expect(page.locator('.component-for-markdown-global p')).toHaveText(
'component for markdown global',
)
await expect(page.locator('.component-for-markdown-import p')).toHaveText(
'component for markdown import',
await expect(page.locator('.component-for-markdown-import-foo p')).toHaveText(
'component for markdown import foo',
)
await expect(page.locator('.component-for-markdown-import-bar p')).toHaveText(
'component for markdown import bar',
)
})
1 change: 1 addition & 0 deletions packages/bundler-vite/src/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './vuepressBuildPlugin.js'
export * from './vuepressConfigPlugin.js'
export * from './vuepressDevPlugin.js'
export * from './vuepressMarkdownPlugin.js'
export * from './vuepressUserConfigPlugin.js'
export * from './vuepressVuePlugin.js'
53 changes: 53 additions & 0 deletions packages/bundler-vite/src/plugins/vuepressMarkdownPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { App } from '@vuepress/core'
import { parsePageContent, renderPageSfcBlocksToVue } from '@vuepress/core'
import { path } from '@vuepress/utils'
import type { Plugin } from 'vite'

/**
* Handle markdown transformation
*/
export const vuepressMarkdownPlugin = ({ app }: { app: App }): Plugin => ({
name: 'vuepress:markdown',

enforce: 'pre',

transform(code, id) {
if (!id.endsWith('.md')) return

// get the matched page by file path (id)
const page = app.pagesMap[id]

// if the page content is not changed, render it to vue component directly
if (page?.content === code) {
return renderPageSfcBlocksToVue(page.sfcBlocks)
}

// parse the markdown content to sfc blocks and render it to vue component
const { sfcBlocks } = parsePageContent({
app,
content: code,
filePath: id,
filePathRelative: path.relative(app.dir.source(), id),
options: {},
})
return renderPageSfcBlocksToVue(sfcBlocks)
},

async handleHotUpdate(ctx) {
if (!ctx.file.endsWith('.md')) return

// read the source code
const code = await ctx.read()

// parse the content to sfc blocks
const { sfcBlocks } = parsePageContent({
app,
content: code,
filePath: ctx.file,
filePathRelative: path.relative(app.dir.source(), ctx.file),
options: {},
})

ctx.read = () => renderPageSfcBlocksToVue(sfcBlocks)
},
})
1 change: 1 addition & 0 deletions packages/bundler-vite/src/plugins/vuepressVuePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export const vuepressVuePlugin = ({
options: ViteBundlerOptions
}): Plugin =>
vuePlugin({
include: [/\.vue$/, /\.md$/],
...options.vuePluginOptions,
})
2 changes: 2 additions & 0 deletions packages/bundler-vite/src/resolveViteConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
vuepressBuildPlugin,
vuepressConfigPlugin,
vuepressDevPlugin,
vuepressMarkdownPlugin,
vuepressUserConfigPlugin,
vuepressVuePlugin,
} from './plugins/index.js'
Expand All @@ -31,6 +32,7 @@ export const resolveViteConfig = ({
},
plugins: [
vuepressConfigPlugin({ app, isBuild, isServer }),
vuepressMarkdownPlugin({ app }),
vuepressDevPlugin({ app }),
vuepressBuildPlugin({ isServer }),
vuepressVuePlugin({ options }),
Expand Down
1 change: 1 addition & 0 deletions packages/bundler-webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"author": "meteorlxy",
"type": "module",
"imports": {
"#vuepress-markdown-loader": "./dist/vuepress-markdown-loader.cjs",
"#vuepress-ssr-loader": "./dist/vuepress-ssr-loader.cjs"
},
"exports": {
Expand Down
12 changes: 0 additions & 12 deletions packages/bundler-webpack/src/build/createClientConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { createRequire } from 'node:module'
import type { App } from '@vuepress/core'
import { fs } from '@vuepress/utils'
import CopyWebpackPlugin from 'copy-webpack-plugin'
Expand All @@ -10,8 +9,6 @@ import { createClientBaseConfig } from '../config/index.js'
import type { WebpackBundlerOptions } from '../types.js'
import { createClientPlugin } from './createClientPlugin.js'

const require = createRequire(import.meta.url)

/**
* Filename of the client manifest file that generated by client plugin
*/
Expand All @@ -27,15 +24,6 @@ export const createClientConfig = async (
isBuild: true,
})

// use internal vuepress-ssr-loader to handle SSR dependencies
config.module
.rule('vue')
.test(/\.vue$/)
.use('vuepress-ssr-loader')
.before('vue-loader')
.loader(require.resolve('#vuepress-ssr-loader'))
.end()

// vuepress client plugin, handle client assets info for ssr
config
.plugin('vuepress-client')
Expand Down
15 changes: 0 additions & 15 deletions packages/bundler-webpack/src/build/createServerConfig.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { createRequire } from 'node:module'
import type { App } from '@vuepress/core'
import type Config from 'webpack-5-chain'
import { createBaseConfig } from '../config/index.js'
import type { WebpackBundlerOptions } from '../types.js'

const require = createRequire(import.meta.url)

export const createServerConfig = async (
app: App,
options: WebpackBundlerOptions,
Expand Down Expand Up @@ -43,17 +40,5 @@ export const createServerConfig = async (
// do not need to minimize server bundle
config.optimization.minimize(false)

// use internal vuepress-ssr-loader to handle SSR dependencies
config.module
.rule('vue')
.test(/\.vue$/)
.use('vuepress-ssr-loader')
.before('vue-loader')
.loader(require.resolve('#vuepress-ssr-loader'))
.options({
app,
})
.end()

return config
}
2 changes: 1 addition & 1 deletion packages/bundler-webpack/src/config/createBaseConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const createBaseConfig = async ({
/**
* module
*/
handleModule({ options, config, isBuild, isServer })
handleModule({ app, options, config, isBuild, isServer })

/**
* plugins
Expand Down
5 changes: 4 additions & 1 deletion packages/bundler-webpack/src/config/handleModule.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { App } from '@vuepress/core'
import type Config from 'webpack-5-chain'
import type { WebpackBundlerOptions } from '../types.js'
import { handleModuleAssets } from './handleModuleAssets.js'
Expand All @@ -11,11 +12,13 @@ import { handleModuleVue } from './handleModuleVue.js'
* Set webpack module
*/
export const handleModule = ({
app,
options,
config,
isBuild,
isServer,
}: {
app: App
options: WebpackBundlerOptions
config: Config
isBuild: boolean
Expand All @@ -27,7 +30,7 @@ export const handleModule = ({
)

// vue files
handleModuleVue({ options, config, isServer })
handleModuleVue({ app, options, config, isBuild, isServer })

// pug files, for templates
handleModulePug({ config })
Expand Down
62 changes: 50 additions & 12 deletions packages/bundler-webpack/src/config/handleModuleVue.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { createRequire } from 'node:module'
import type { App } from '@vuepress/core'
import type { VueLoaderOptions } from 'vue-loader'
import { VueLoaderPlugin } from 'vue-loader'
import type Config from 'webpack-5-chain'
import type { VuepressMarkdownLoaderOptions } from '../loaders/vuepressMarkdownLoader'
import type { WebpackBundlerOptions } from '../types.js'

const require = createRequire(import.meta.url)
Expand All @@ -10,26 +12,62 @@ const require = createRequire(import.meta.url)
* Set webpack module to handle vue files
*/
export const handleModuleVue = ({
app,
options,
config,
isBuild,
isServer,
}: {
app: App
options: WebpackBundlerOptions
config: Config
isBuild: boolean
isServer: boolean
}): void => {
// .vue files
config.module
.rule('vue')
.test(/\.vue$/)
// use vue-loader
.use('vue-loader')
.loader(require.resolve('vue-loader'))
.options({
...options.vue,
isServerBuild: isServer,
} as VueLoaderOptions)
.end()
const applyVuePipeline = ({
rule,
isMd,
}: {
rule: Config.Rule
isMd: boolean
}): void => {
// use internal vuepress-ssr-loader to handle SSR dependencies
if (isBuild) {
rule
.use('vuepress-ssr-loader')
.loader(require.resolve('#vuepress-ssr-loader'))
.end()
}

// use official vue-loader
rule
.use('vue-loader')
.loader(require.resolve('vue-loader'))
.options({
...options.vue,
isServerBuild: isServer,
} satisfies VueLoaderOptions)
.end()

// use internal vuepress-markdown-loader to handle markdown files
if (isMd) {
rule
.use('vuepress-markdown-loader')
.loader(require.resolve('#vuepress-markdown-loader'))
.options({ app } satisfies VuepressMarkdownLoaderOptions)
.end()
}
}

applyVuePipeline({
rule: config.module.rule('md').test(/\.md$/),
isMd: true,
})

applyVuePipeline({
rule: config.module.rule('vue').test(/\.vue$/),
isMd: false,
})

// use vue-loader plugin
config.plugin('vue-loader').use(VueLoaderPlugin)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const loader = require('./vuepressMarkdownLoader.js')

module.exports = loader.vuepressMarkdownLoader
37 changes: 37 additions & 0 deletions packages/bundler-webpack/src/loaders/vuepressMarkdownLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { App } from '@vuepress/core'
import type { LoaderDefinitionFunction } from 'webpack'

export interface VuepressMarkdownLoaderOptions {
app: App
}

/**
* A webpack loader to transform markdown content to vue component
*/
export const vuepressMarkdownLoader: LoaderDefinitionFunction<VuepressMarkdownLoaderOptions> =
async function vuepressMarkdownLoader(source) {
// import esm dependencies
const [{ parsePageContent, renderPageSfcBlocksToVue }, { path }] =
await Promise.all([import('@vuepress/core'), import('@vuepress/utils')])

// get app instance from loader options
const { app } = this.getOptions()

// get the matched page by file path
const page = app.pagesMap[this.resourcePath]

// if the page content is not changed, render it to vue component directly
if (page?.content === source) {
return renderPageSfcBlocksToVue(page.sfcBlocks)
}

// parse the markdown content to sfc blocks and render it to vue component
const { sfcBlocks } = parsePageContent({
app,
content: source,
filePath: this.resourcePath,
filePathRelative: path.relative(app.dir.source(), this.resourcePath),
options: {},
})
return renderPageSfcBlocksToVue(sfcBlocks)
}
1 change: 1 addition & 0 deletions packages/bundler-webpack/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default defineConfig([
{
...shared,
entry: {
'vuepress-markdown-loader': './src/loaders/vuepressMarkdownLoader.cts',
'vuepress-ssr-loader': './src/loaders/vuepressSsrLoader.cts',
},
format: ['cjs'],
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/app/appInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export const appInit = async (app: App): Promise<void> => {
app.markdown = await resolveAppMarkdown(app)

// create pages
app.pages = await resolveAppPages(app)
const { pages, pagesMap } = await resolveAppPages(app)
app.pages = pages
app.pagesMap = pagesMap

// plugin hook: onInitialized
await app.pluginApi.hooks.onInitialized.process(app)
Expand Down
Loading
Loading