Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove temp page files and load page component via bundler (close #1584) #1606

Draft
wants to merge 22 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 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
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
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 eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default vuepress(
'__dirname',
'_context',
'_pageChunk',
'_pageData',
'_registeredComponents',
],
},
Expand Down
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'
46 changes: 46 additions & 0 deletions packages/bundler-vite/src/plugins/vuepressMarkdownPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { App } from '@vuepress/core'
import { createPage, renderPageToVue } from '@vuepress/core'
import type { Plugin } from 'vite'

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

enforce: 'pre',

async 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 renderPageToVue(app, page)
}

// create a new page with the new content
const newPage = await createPage(app, {
content: code,
filePath: id,
})
return renderPageToVue(app, newPage)
},

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

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

// create a new page with the new content
const newPage = await createPage(app, {
content: code,
filePath: ctx.file,
})

ctx.read = () => renderPageToVue(app, newPage)
},
})
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
57 changes: 45 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,57 @@ 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 handleVue = ({
lang,
test,
}: {
lang: 'md' | 'vue'
test: RegExp
}): void => {
const rule = config.module.rule(lang).test(test)

// 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 (lang === 'md') {
rule
.use('vuepress-markdown-loader')
.loader(require.resolve('#vuepress-markdown-loader'))
.options({ app } satisfies VuepressMarkdownLoaderOptions)
.end()
}
}

handleVue({ lang: 'md', test: /\.md$/ })
handleVue({ lang: 'vue', test: /\.vue$/ })

// 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
33 changes: 33 additions & 0 deletions packages/bundler-webpack/src/loaders/vuepressMarkdownLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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 { createPage, renderPageToVue } = await import('@vuepress/core')

// 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 renderPageToVue(app, page)
}

// create a new page with the new content
const newPage = await createPage(app, {
content: source,
filePath: this.resourcePath,
})
return renderPageToVue(app, newPage)
}
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
Loading
Loading