Skip to content

Commit

Permalink
refactor: remove temp page files and load page component via bundler
Browse files Browse the repository at this point in the history
  • Loading branch information
meteorlxy committed Sep 10, 2024
1 parent 8a90ce9 commit b4ff6a7
Show file tree
Hide file tree
Showing 31 changed files with 319 additions and 345 deletions.
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

0 comments on commit b4ff6a7

Please sign in to comment.