Skip to content

Commit

Permalink
feat: inject default export
Browse files Browse the repository at this point in the history
  • Loading branch information
meteorlxy committed Sep 11, 2024
1 parent 3cfbb6f commit d45c678
Showing 1 changed file with 56 additions and 24 deletions.
80 changes: 56 additions & 24 deletions packages/core/src/page/renderPageToVue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isString } from '@vuepress/shared'
import { path } from '@vuepress/utils'
import type { App, Page } from '../types/index.js'

const TEMPLATE_WRAPPER_TAG_OPEN = '<div>'
Expand All @@ -10,6 +11,13 @@ const SCRIPT_TAG_CLOSE = '</script>'
const SCRIPT_TAG_OPEN_LANG_TS_REGEX = /<\s*script[^>]*\blang=['"]ts['"][^>]*/
const SCRIPT_TAG_OPEN_LANG_TS = '<script lang="ts">'

const SCRIPT_DEFAULT_EXPORT_REGEX = /((?:^|\n|;)\s*)export(\s*)default/
const SCRIPT_DEFAULT_NAMED_EXPORT_REGEX =
/((?:^|\n|;)\s*)export(.+)as(\s*)default/

const SCRIPT_DEFAULT_EXPORT_CODE_TEMPLATE_OUTLET = '__SCRIPT_DEFAULT_EXPORT__'
const SCRIPT_DEFAULT_EXPORT_CODE_TEMPLATE = `export default { name: ${SCRIPT_DEFAULT_EXPORT_CODE_TEMPLATE_OUTLET} }`

const PAGE_DATA_CODE_VAR_NAME = '_pageData'
const PAGE_DATA_CODE_TEMPLATE_OUTLET = '__PAGE_DATA__'
const PAGE_DATA_CODE_TEMPLATE = `export const ${PAGE_DATA_CODE_VAR_NAME} = JSON.parse(${PAGE_DATA_CODE_TEMPLATE_OUTLET})`
Expand All @@ -27,37 +35,65 @@ if (import.meta.hot) {
}
`

/**
* Util to resolve the page data code
*/
const resolvePageDataCode = (data: Page['data']): string =>
PAGE_DATA_CODE_TEMPLATE.replace(
PAGE_DATA_CODE_TEMPLATE_OUTLET,
JSON.stringify(JSON.stringify(data)),
)

/**
* Util to resolve the open tag of script block
*/
const resolveScriptTagOpen = (sfcBlocks: Page['sfcBlocks']): string => {
const resolveScriptTagOpen = (page: Page): string => {
// use existing script open tag
if (sfcBlocks.script?.tagOpen) {
return sfcBlocks.script.tagOpen
if (page.sfcBlocks.script?.tagOpen) {
return page.sfcBlocks.script.tagOpen
}
// if the setup script block is using typescript, we should use the same language for script block
const isUsingTs = sfcBlocks.scriptSetup?.tagOpen.match(
const isUsingTs = page.sfcBlocks.scriptSetup?.tagOpen.match(
SCRIPT_TAG_OPEN_LANG_TS_REGEX,
)
return isUsingTs ? SCRIPT_TAG_OPEN_LANG_TS : SCRIPT_TAG_OPEN
}

/**
* Util to resolve the default export code
*/
const resolveDefaultExportCode = (page: Page): string =>
SCRIPT_DEFAULT_EXPORT_CODE_TEMPLATE.replace(
SCRIPT_DEFAULT_EXPORT_CODE_TEMPLATE_OUTLET,
JSON.stringify(path.basename(page.chunkFilePath)),
)

/**
* Util to resolve the page data code
*/
const resolvePageDataCode = (page: Page): string =>
PAGE_DATA_CODE_TEMPLATE.replace(
PAGE_DATA_CODE_TEMPLATE_OUTLET,
JSON.stringify(JSON.stringify(page.data)),
)

/**
* Resolve the stripped content of script block
*/
const resolveScriptContentStripped = (app: App, page: Page): string => {
const rawContentStripped = page.sfcBlocks.script?.contentStripped
const hasDefaultExport = rawContentStripped
? SCRIPT_DEFAULT_EXPORT_REGEX.test(rawContentStripped) ||
SCRIPT_DEFAULT_NAMED_EXPORT_REGEX.test(rawContentStripped)
: false
return [
rawContentStripped,
resolvePageDataCode(page), // inject page data code
!hasDefaultExport && resolveDefaultExportCode(page), // inject default export with component name
app.env.isDev && HMR_CODE, // inject HMR code in dev mode
]
.filter(isString)
.join('\n')
}

/**
* Render page to vue component
*/
export const renderPageToVue = (
app: App,
{ data, sfcBlocks }: Page,
): string => {
export const renderPageToVue = (app: App, page: Page): string => {
const { sfcBlocks } = page

// get the content of template block
// #688: wrap the content of `<template>` with a `<div>` to avoid some potential issues of fragment component
const templateContent =
sfcBlocks.template &&
Expand All @@ -69,14 +105,10 @@ export const renderPageToVue = (
sfcBlocks.template.tagClose,
].join('')

// inject page data code and HMR code into the script content
const scriptTagOpen = resolveScriptTagOpen(sfcBlocks)
const pageDataCode = resolvePageDataCode(data)
// get the content of script block
const scriptContent = [
scriptTagOpen,
sfcBlocks.script?.contentStripped,
pageDataCode,
app.env.isDev && HMR_CODE,
resolveScriptTagOpen(page),
resolveScriptContentStripped(app, page),
sfcBlocks.script?.tagClose ?? SCRIPT_TAG_CLOSE,
]
.filter(isString)
Expand Down

0 comments on commit d45c678

Please sign in to comment.