diff --git a/superset-frontend/packages/superset-ui-core/src/components/SafeMarkdown.tsx b/superset-frontend/packages/superset-ui-core/src/components/SafeMarkdown.tsx index b5ed0d9941ff..02db7dadbc63 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/SafeMarkdown.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/SafeMarkdown.tsx @@ -16,10 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { useMemo } from 'react'; -import ReactMarkdown from 'react-markdown'; +import { useEffect, useMemo, useState } from 'react'; import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; -import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; import { mergeWith, isArray } from 'lodash'; import { FeatureFlag, isFeatureEnabled } from '../utils'; @@ -45,11 +43,21 @@ function SafeMarkdown({ htmlSchemaOverrides = {}, }: SafeMarkdownProps) { const escapeHtml = isFeatureEnabled(FeatureFlag.EscapeMarkdownHtml); + const [rehypeRawPlugin, setRehypeRawPlugin] = useState(null); + const [ReactMarkdown, setReactMarkdown] = useState(null); + useEffect(() => { + Promise.all([import('rehype-raw'), import('react-markdown')]).then( + ([rehypeRaw, ReactMarkdown]) => { + setRehypeRawPlugin(() => rehypeRaw.default); + setReactMarkdown(() => ReactMarkdown.default); + }, + ); + }, []); const rehypePlugins = useMemo(() => { const rehypePlugins: any = []; - if (!escapeHtml) { - rehypePlugins.push(rehypeRaw); + if (!escapeHtml && rehypeRawPlugin) { + rehypePlugins.push(rehypeRawPlugin); if (htmlSanitization) { const schema = getOverrideHtmlSchema( defaultSchema, @@ -59,7 +67,11 @@ function SafeMarkdown({ } } return rehypePlugins; - }, [escapeHtml, htmlSanitization, htmlSchemaOverrides]); + }, [escapeHtml, htmlSanitization, htmlSchemaOverrides, rehypeRawPlugin]); + + if (!ReactMarkdown || !rehypeRawPlugin) { + return null; + } // React Markdown escapes HTML by default return (