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

fix: handle vite constants replacement (close #419) #888

Merged
merged 1 commit into from
Jul 1, 2022
Merged
Changes from all commits
Commits
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
72 changes: 44 additions & 28 deletions src/node/markdownToVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,7 @@ export async function createMarkdownToVueRenderFn(

pages = pages.map((p) => slash(p.replace(/\.md$/, '')))

const userDefineRegex = userDefines
? new RegExp(
`\\b(${Object.keys(userDefines)
.map((key) => key.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'))
.join('|')})`,
'g'
)
: null
const replaceRegex = genReplaceRegexp(userDefines, isBuild)

return async (
src: string,
Expand Down Expand Up @@ -74,24 +67,9 @@ export async function createMarkdownToVueRenderFn(
md.__path = file
md.__relativePath = relativePath

let html = md.render(content)
const html = md.render(content)
const data = md.__data

if (isBuild) {
// avoid env variables being replaced by vite
html = html
.replace(/\bimport\.meta/g, 'import.<wbr/>meta')
.replace(/\bprocess\.env/g, 'process.<wbr/>env')

// also avoid replacing vite user defines
if (userDefineRegex) {
html = html.replace(
userDefineRegex,
(_) => `${_[0]}<wbr/>${_.slice(1)}`
)
}
}

// validate data.links
const deadLinks: string[] = []
const recordDeadLink = (url: string) => {
Expand Down Expand Up @@ -149,8 +127,14 @@ export async function createMarkdownToVueRenderFn(
}

const vueSrc =
genPageDataCode(data.hoistedTags || [], pageData).join('\n') +
`\n<template><div>${html}</div></template>`
genPageDataCode(data.hoistedTags || [], pageData, replaceRegex).join(
'\n'
) +
`\n<template><div>${replaceConstants(
html,
replaceRegex,
vueTemplateBreaker
)}</div></template>`

debug(`[render] ${file} in ${Date.now() - start}ms.`)

Expand All @@ -171,10 +155,42 @@ const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/
const scriptClientRE = /<\s*script[^>]*\bclient\b[^>]*/
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/
const jsStringBreaker = '\u200b'
const vueTemplateBreaker = '<wbr>'

function genReplaceRegexp(
userDefines: Record<string, any> = {},
isBuild: boolean
): RegExp {
// `process.env` need to be handled in both dev and build
// @see https://github.com/vitejs/vite/blob/cad27ee8c00bbd5aeeb2be9bfb3eb164c1b77885/packages/vite/src/node/plugins/clientInjections.ts#L57-L64
const replacements = ['process.env']
if (isBuild) {
replacements.push('import.meta', ...Object.keys(userDefines))
}
return new RegExp(
`\\b(${replacements
.map((key) => key.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'))
.join('|')})`,
'g'
)
}

/**
* To avoid env variables being replaced by vite:
* - insert `'\u200b'` char into those strings inside js string (page data)
* - insert `<wbr>` tag into those strings inside html string (vue template)
*
* @see https://vitejs.dev/guide/env-and-mode.html#production-replacement
*/
function replaceConstants(str: string, replaceRegex: RegExp, breaker: string) {
return str.replace(replaceRegex, (_) => `${_[0]}${breaker}${_.slice(1)}`)
}

function genPageDataCode(tags: string[], data: PageData) {
function genPageDataCode(tags: string[], data: PageData, replaceRegex: RegExp) {
const dataJson = JSON.stringify(data)
const code = `\nexport const __pageData = JSON.parse(${JSON.stringify(
JSON.stringify(data)
replaceConstants(dataJson, replaceRegex, jsStringBreaker)
)})`

const existingScriptIndex = tags.findIndex((tag) => {
Expand Down