From 563c286a9dcfd13702e5292dc85facd2605007d5 Mon Sep 17 00:00:00 2001 From: qixuan <58852732+GiveMe-A-Name@users.noreply.github.com> Date: Thu, 14 Dec 2023 18:52:58 +0800 Subject: [PATCH] Fix/ssr unsafe replace (#5094) --- .changeset/lazy-impalas-cheer.md | 6 +++ .../runtime/plugin-runtime/src/ssr/index.tsx | 5 ++- .../src/ssr/serverRender/constants.ts | 11 ++++++ .../src/ssr/serverRender/helmet.ts | 7 ++-- .../src/ssr/serverRender/index.ts | 4 +- .../renderToStream/buildTemplate.after.ts | 6 ++- .../renderToStream/bulidTemplate.before.ts | 5 ++- .../serverRender/renderToString/buildHtml.ts | 39 +++++++------------ .../ssr/serverRender/renderToString/entry.ts | 7 +--- .../src/ssr/serverRender/utils.ts | 22 ++++++++--- 10 files changed, 67 insertions(+), 45 deletions(-) create mode 100644 .changeset/lazy-impalas-cheer.md create mode 100644 packages/runtime/plugin-runtime/src/ssr/serverRender/constants.ts diff --git a/.changeset/lazy-impalas-cheer.md b/.changeset/lazy-impalas-cheer.md new file mode 100644 index 000000000000..92424564fecc --- /dev/null +++ b/.changeset/lazy-impalas-cheer.md @@ -0,0 +1,6 @@ +--- +'@modern-js/runtime': patch +--- + +fix: the Helment replace may meets special char +fix: the Helment 替换可能会遇到特殊字符,导致替换出问题 diff --git a/packages/runtime/plugin-runtime/src/ssr/index.tsx b/packages/runtime/plugin-runtime/src/ssr/index.tsx index 591863f8da18..a78158fa2ad9 100644 --- a/packages/runtime/plugin-runtime/src/ssr/index.tsx +++ b/packages/runtime/plugin-runtime/src/ssr/index.tsx @@ -9,7 +9,10 @@ import { } from './serverRender/types'; import { WithCallback } from './react/withCallback'; import { formatClient, mockResponse, isReact18 } from './utils'; -import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID } from './serverRender/utils'; +import { + ROUTER_DATA_JSON_ID, + SSR_DATA_JSON_ID, +} from './serverRender/constants'; declare module '../core' { interface SSRContainer { diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/constants.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/constants.ts new file mode 100644 index 000000000000..0364ea85f507 --- /dev/null +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/constants.ts @@ -0,0 +1,11 @@ +export const HTML_PLACEHOLDER = ''; + +export const SSR_DATA_PLACEHOLDER = ''; + +export const CHUNK_JS_PLACEHOLDER = ''; + +export const CHUNK_CSS_PLACEHOLDER = ''; + +export const SSR_DATA_JSON_ID = '__MODERN_SSR_DATA__'; + +export const ROUTER_DATA_JSON_ID = '__MODERN_ROUTER_DATA__'; diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/helmet.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/helmet.ts index 1afdf38bde02..d13c9e2e857c 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/helmet.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/helmet.ts @@ -1,6 +1,7 @@ // 用于 react-helmet 正则替换 import { EOL } from 'os'; import { HelmetData } from 'react-helmet'; +import { unsafeReplace } from './utils'; const RE_HTML_ATTR = /]*>/; const RE_BODY_ATTR = /]*>/; @@ -14,12 +15,12 @@ export default function helmet(content: string, helmetData: HelmetData) { let result = content; const bodyAttributes = helmetData.bodyAttributes.toString(); if (bodyAttributes) { - result = result.replace(RE_BODY_ATTR, ``); + result = unsafeReplace(result, RE_BODY_ATTR, ``); } const htmlAttributes = helmetData.htmlAttributes.toString(); if (htmlAttributes) { - result = result.replace(RE_HTML_ATTR, ``); + result = unsafeReplace(result, RE_HTML_ATTR, ``); } const base = helmetData.base.toString(); @@ -50,5 +51,5 @@ export default function helmet(content: string, helmetData: HelmetData) { return pre + (cur.length > 0 ? ` ${cur}${EOL}` : ''); }, ''); - return result.replace(RE_LAST_IN_HEAD, `${helmetStr}`); + return unsafeReplace(result, RE_LAST_IN_HEAD, `${helmetStr}`); } diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/index.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/index.ts index ace0ecbbc3d8..5c2b2fb12475 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/index.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/index.ts @@ -3,14 +3,14 @@ import { isReact18 } from '../utils'; import { ServerRenderOptions } from './types'; -import { CSS_CHUNKS_PLACEHOLDER } from './utils'; +import { CHUNK_JS_PLACEHOLDER } from './constants'; export default async function serverRender(options: ServerRenderOptions) { if (options.context.ssrContext?.template) { options.context.ssrContext.template = options.context.ssrContext?.template.replace( '', - `${CSS_CHUNKS_PLACEHOLDER}`, + `${CHUNK_JS_PLACEHOLDER}`, ); } diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/buildTemplate.after.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/buildTemplate.after.ts index 36336d36ae2d..09b40b2fd4a1 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/buildTemplate.after.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/buildTemplate.after.ts @@ -1,6 +1,7 @@ import { serializeJson } from '@modern-js/runtime-utils/node'; import { RenderLevel, RuntimeContext } from '../types'; -import { attributesToString } from '../utils'; +import { attributesToString, unsafeReplace } from '../utils'; +import { SSR_DATA_PLACEHOLDER } from '../constants'; import { BuildTemplateCb, buildTemplate } from './buildTemplate.share'; type BuildShellAfterTemplateOptions = { @@ -16,7 +17,8 @@ export function buildShellAfterTemplate( function injectSSRDataScript(template: string) { const ssrDataScript = buildSSRDataScript(); - return template.replace('', ssrDataScript); + + return unsafeReplace(template, SSR_DATA_PLACEHOLDER, ssrDataScript); function buildSSRDataScript() { const { diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/bulidTemplate.before.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/bulidTemplate.before.ts index 075ca20b9697..4b6717a3576e 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/bulidTemplate.before.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToStream/bulidTemplate.before.ts @@ -3,7 +3,8 @@ import ReactHelmet, { HelmetData } from 'react-helmet'; import { matchRoutes } from '@modern-js/runtime-utils/router'; import helmetReplace from '../helmet'; import { RuntimeContext } from '../types'; -import { CSS_CHUNKS_PLACEHOLDER } from '../utils'; +import { CHUNK_CSS_PLACEHOLDER } from '../constants'; +import { unsafeReplace } from '../utils'; import { HEAD_REG_EXP, BuildTemplateCb, @@ -30,7 +31,7 @@ function getHeadTemplate(beforeEntryTemplate: string, context: RuntimeContext) { return buildTemplate(headTemplate, callbacks); function injectCss(headTemplate: string) { - return headTemplate.replace(CSS_CHUNKS_PLACEHOLDER, getCssChunks()); + return unsafeReplace(headTemplate, CHUNK_CSS_PLACEHOLDER, getCssChunks()); function getCssChunks() { const { routeManifest, routerContext, routes } = context; diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/buildHtml.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/buildHtml.ts index 5b2a38afd0c0..c86ed1f4ddd8 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/buildHtml.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/buildHtml.ts @@ -1,41 +1,32 @@ -export type BuildHtmlCb = (tempalte: string) => string; +import { unsafeReplace } from '../utils'; +import { + HTML_PLACEHOLDER, + SSR_DATA_PLACEHOLDER, + CHUNK_JS_PLACEHOLDER, + CHUNK_CSS_PLACEHOLDER, +} from '../constants'; -/** - * It is unsafe unsafeReplace, only support serachValue exsit one time. - * @param source - * @param searchValue - * @param replaceValue - * @returns - */ -function unsafeReplace( - source: string, - searchValue: RegExp | string, - replaceValue: string, -) { - const [s1, s2] = source.split(searchValue); - return s1 + replaceValue + s2; -} +export type BuildHtmlCb = (tempalte: string) => string; export function buildHtml(template: string, callbacks: BuildHtmlCb[]) { return callbacks.reduce((tmp, cb) => cb(tmp), template); } export function createReplaceHtml(html: string): BuildHtmlCb { - const HTML_REMARK = ''; - return (template: string) => unsafeReplace(template, HTML_REMARK, html); + return (template: string) => unsafeReplace(template, HTML_PLACEHOLDER, html); } export function createReplaceSSRDataScript(data: string): BuildHtmlCb { - const SSR_DATA_REMARK = ''; - return (template: string) => unsafeReplace(template, SSR_DATA_REMARK, data); + return (template: string) => + unsafeReplace(template, SSR_DATA_PLACEHOLDER, data); } export function createReplaceChunkJs(js: string): BuildHtmlCb { - const CHUNK_JS_REMARK = ''; - return (template: string) => unsafeReplace(template, CHUNK_JS_REMARK, js); + return (template: string) => + unsafeReplace(template, CHUNK_JS_PLACEHOLDER, js); } export function createReplaceChunkCss(css: string): BuildHtmlCb { - const CHUNK_CSS_REG = ''; - return (template: string) => unsafeReplace(template, CHUNK_CSS_REG, css); + return (template: string) => + unsafeReplace(template, CHUNK_CSS_PLACEHOLDER, css); } diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/entry.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/entry.ts index fd36b9e64f09..650a599b6756 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/entry.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/renderToString/entry.ts @@ -13,11 +13,8 @@ import { SSRServerContext, } from '../types'; import prefetch from '../../prefetch'; -import { - ROUTER_DATA_JSON_ID, - SSR_DATA_JSON_ID, - attributesToString, -} from '../utils'; +import { ROUTER_DATA_JSON_ID, SSR_DATA_JSON_ID } from '../constants'; +import { attributesToString } from '../utils'; import { SSRErrors, SSRTimings, SSRTracker } from '../tracker'; import { createLoadableCollector } from './loadable'; import { createRender } from './render'; diff --git a/packages/runtime/plugin-runtime/src/ssr/serverRender/utils.ts b/packages/runtime/plugin-runtime/src/ssr/serverRender/utils.ts index 8c1f4f49829d..282377fe9ed9 100644 --- a/packages/runtime/plugin-runtime/src/ssr/serverRender/utils.ts +++ b/packages/runtime/plugin-runtime/src/ssr/serverRender/utils.ts @@ -1,12 +1,22 @@ -export const CSS_CHUNKS_PLACEHOLDER = ''; - -export const SSR_DATA_JSON_ID = '__MODERN_SSR_DATA__'; - -export const ROUTER_DATA_JSON_ID = '__MODERN_ROUTER_DATA__'; - export function attributesToString(attributes: Record) { // Iterate through the properties and convert them into a string, only including properties that are not undefined. return Object.entries(attributes).reduce((str, [key, value]) => { return value === undefined ? str : `${str} ${key}="${value}"`; }, ''); } + +/** + * It is unsafe unsafeReplace, only support serachValue exsit one time. + * @param source + * @param searchValue + * @param replaceValue + * @returns + */ +export function unsafeReplace( + source: string, + searchValue: RegExp | string, + replaceValue: string, +) { + const [s1, s2] = source.split(searchValue); + return s1 + replaceValue + s2; +}