diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts index 049bd8d8ae05..86a07750fd4d 100644 --- a/src/node/markdownToVue.ts +++ b/src/node/markdownToVue.ts @@ -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, @@ -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.meta') - .replace(/\bprocess\.env/g, 'process.env') - - // also avoid replacing vite user defines - if (userDefineRegex) { - html = html.replace( - userDefineRegex, - (_) => `${_[0]}${_.slice(1)}` - ) - } - } - // validate data.links const deadLinks: string[] = [] const recordDeadLink = (url: string) => { @@ -149,8 +127,14 @@ export async function createMarkdownToVueRenderFn( } const vueSrc = - genPageDataCode(data.hoistedTags || [], pageData).join('\n') + - `\n` + genPageDataCode(data.hoistedTags || [], pageData, replaceRegex).join( + '\n' + ) + + `\n` debug(`[render] ${file} in ${Date.now() - start}ms.`) @@ -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 = '' + +function genReplaceRegexp( + userDefines: Record = {}, + 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 `` 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) => {