Remplace react-markdown par markdown-to-jsx
La version utilisée de react-markdown n'était pas compatible avec ViteJS. J'ai tenté la mise à jour vers la v7 qui est publiée sous forme de ES Module, ce qui nécessitait d'intégrer plusieurs changements d'API. En m'y attelant j'ai réalisé que la motivation première de react-markdown était de ne surtout pas utiliser `dangerouslySetInnerHTML`, ce qui est utile pour les cas d'usages où le markdown n'est pas digne de confiance (message d'utilisateurs par exemple). Cette contrainte oblige à alourdir sensiblement la quantité de JavaScript à charger et à évaluer. Anisi dans certains markdown que l'on affiche, on utilise la balise HTML `<sup>`, qui n'est pas parsée nativement pas react-markdown. Comme on ne peut pas faire de `dangerouslySetInnerHTML` il faut intégrer un parseur HTML complet qui rajout 60kb, juste pour quelques occurences de `<sup>` dans les pages nouveautés. Dans notre cas d'usage reparser tout le html en Javascript, n'est pas utile. markdown-to-jsx semble plus adapté et beaucoup plus léger. Par ailleurs le paquet est 5 fois plus utilisé que react-markdown : https://www.npmtrends.com/react-markdown-vs-markdown-to-jsxpull/1967/head
parent
e6e2ec2c9e
commit
9ad8b0f186
|
@ -63,6 +63,7 @@
|
|||
"algoliasearch": "^4.10.2",
|
||||
"fuse.js": "^6.4.6",
|
||||
"iframe-resizer": "^4.1.1",
|
||||
"markdown-to-jsx": "^7.1.5",
|
||||
"modele-social": "^0.5.0",
|
||||
"publicodes": "^1.0.0-beta.25",
|
||||
"publicodes-react": "^1.0.0-beta.25",
|
||||
|
@ -75,7 +76,6 @@
|
|||
"react-i18next": "^11.0.0",
|
||||
"react-instantsearch": "^6.11.2",
|
||||
"react-instantsearch-dom": "^6.11.2",
|
||||
"react-markdown": "^4.1.0",
|
||||
"react-redux": "^7.0.3",
|
||||
"react-router-dom": "^5.1.1",
|
||||
"react-signature-pad-wrapper": "^1.2.11",
|
||||
|
|
|
@ -130,7 +130,7 @@ function ActivitéMixte() {
|
|||
</Checkbox>
|
||||
</Trans>
|
||||
<ButtonHelp type="aide" title={rule.title} light>
|
||||
<Markdown source={rule.rawNode.description} />
|
||||
<Markdown>{rule.rawNode.description ?? ''}</Markdown>
|
||||
</ButtonHelp>
|
||||
</StyledActivitéMixteContainer>
|
||||
)
|
||||
|
|
|
@ -67,7 +67,7 @@ export default function Notifications() {
|
|||
<Notification className="notification" key={dottedName}>
|
||||
<Emoji emoji={sévérité == 'avertissement' ? '⚠️' : '💁🏻'} />
|
||||
<NotificationContent className="notificationText">
|
||||
<Markdown source={résumé ?? description} />{' '}
|
||||
<Markdown>{résumé ?? description ?? ''}</Markdown>{' '}
|
||||
{résumé && (
|
||||
<RuleLink dottedName={dottedName as DottedName}>
|
||||
<Trans>En savoir plus</Trans>
|
||||
|
|
|
@ -111,7 +111,7 @@ function RadioChoice({
|
|||
</Radio>{' '}
|
||||
{node.rawNode.description && (
|
||||
<ButtonHelp type="info" light title={node.title}>
|
||||
<Markdown source={node.rawNode.description} />
|
||||
<Markdown>{node.rawNode.description ?? ''}</Markdown>
|
||||
</ButtonHelp>
|
||||
)}
|
||||
</span>
|
||||
|
|
|
@ -28,7 +28,7 @@ export function ExplicableRule({
|
|||
title={rule.title}
|
||||
light={light}
|
||||
>
|
||||
<Markdown source={rule.rawNode.description} />
|
||||
<Markdown>{rule.rawNode.description}</Markdown>
|
||||
</ButtonHelp>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function CotisationsForfaitaires() {
|
|||
<Value expression="dirigeant . indépendant . cotisations et contributions . début activité" />
|
||||
</Intro>
|
||||
|
||||
<Markdown source={rule.rawNode.description} />
|
||||
<Markdown>{rule.rawNode.description ?? ''}</Markdown>
|
||||
{rule.rawNode.références && (
|
||||
<>
|
||||
<Spacing lg />
|
||||
|
|
|
@ -14,7 +14,7 @@ export default function CotisationsRégularisation() {
|
|||
<FromBottom>
|
||||
<div>
|
||||
<H3 as="h2">{rule.title}</H3>
|
||||
<Markdown source={rule.rawNode.description} />
|
||||
<Markdown>{rule.rawNode.description ?? ''}</Markdown>
|
||||
|
||||
{rule.rawNode.références && (
|
||||
<>
|
||||
|
|
|
@ -80,7 +80,7 @@ export function CheckItem({
|
|||
`}
|
||||
>
|
||||
{typeof explanations === 'string' ? (
|
||||
<Markdown source={explanations} />
|
||||
<Markdown>{explanations}</Markdown>
|
||||
) : (
|
||||
explanations
|
||||
)}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Link } from 'DesignSystem/typography/link'
|
|||
import { Li, Ul } from 'DesignSystem/typography/list'
|
||||
import { Body } from 'DesignSystem/typography/paragraphs'
|
||||
import React, { useContext, useEffect } from 'react'
|
||||
import ReactMarkdown, { ReactMarkdownProps } from 'react-markdown'
|
||||
import MarkdownToJsx from 'markdown-to-jsx'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { SiteNameContext } from '../../Provider'
|
||||
import Emoji from './Emoji'
|
||||
|
@ -12,7 +12,6 @@ import Emoji from './Emoji'
|
|||
const internalURLs = {
|
||||
'mon-entreprise.urssaf.fr': 'mon-entreprise',
|
||||
'mycompanyinfrance.urssaf.fr': 'infrance',
|
||||
'publi.codes': 'publicodes',
|
||||
} as const
|
||||
|
||||
export function LinkRenderer({
|
||||
|
@ -33,14 +32,6 @@ export function LinkRenderer({
|
|||
)
|
||||
}
|
||||
|
||||
if (href && !href.startsWith('http')) {
|
||||
return (
|
||||
<Link to={href} {...otherProps}>
|
||||
{children}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
// Convert absolute links that reload the full app into in-app links handled
|
||||
// by react-router.
|
||||
for (const domain of Object.keys(internalURLs)) {
|
||||
|
@ -67,8 +58,7 @@ const TextRenderer = ({ children }: { children: string }) => (
|
|||
<Emoji emoji={children} />
|
||||
)
|
||||
|
||||
type MarkdownProps = ReactMarkdownProps & {
|
||||
source: string | undefined
|
||||
type MarkdownProps = React.ComponentProps<typeof MarkdownToJsx> & {
|
||||
className?: string
|
||||
}
|
||||
|
||||
|
@ -100,29 +90,34 @@ const CodeBlock = ({
|
|||
)
|
||||
|
||||
export const Markdown = ({
|
||||
source,
|
||||
className = '',
|
||||
renderers = {},
|
||||
children,
|
||||
components = {},
|
||||
...otherProps
|
||||
}: MarkdownProps) => (
|
||||
<ReactMarkdown
|
||||
transformLinkUri={(src) => src}
|
||||
source={source}
|
||||
className={`markdown ${className}`}
|
||||
renderers={{
|
||||
link: LinkRenderer,
|
||||
paragraph: Body,
|
||||
text: TextRenderer,
|
||||
code: CodeBlock,
|
||||
list: Ul,
|
||||
strong: Strong,
|
||||
listItem: Li,
|
||||
heading: Heading,
|
||||
emphasis: ({ children }) => <small>{children}</small>,
|
||||
...renderers,
|
||||
}}
|
||||
<MarkdownToJsx
|
||||
{...otherProps}
|
||||
/>
|
||||
options={{
|
||||
...otherProps.options,
|
||||
overrides: {
|
||||
h1: H1,
|
||||
h2: H2,
|
||||
h3: H3,
|
||||
h4: H4,
|
||||
h5: H5,
|
||||
h6: H6,
|
||||
p: Body,
|
||||
strong: Strong,
|
||||
a: LinkRenderer,
|
||||
ul: Ul,
|
||||
li: Li,
|
||||
code: CodeBlock,
|
||||
span: TextRenderer,
|
||||
...components,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</MarkdownToJsx>
|
||||
)
|
||||
|
||||
export const MarkdownWithAnchorLinks = ({
|
||||
|
|
|
@ -54,7 +54,7 @@ export default function Budget() {
|
|||
<H1>
|
||||
Budget <Emoji emoji="💶" />
|
||||
</H1>
|
||||
<Markdown source={intro} />
|
||||
<Markdown>{intro}</Markdown>
|
||||
<H2>Budget consommé</H2>
|
||||
<Grid item xs={6} sm={4}>
|
||||
<Select
|
||||
|
@ -72,7 +72,7 @@ export default function Budget() {
|
|||
</Select>
|
||||
</Grid>
|
||||
|
||||
<Markdown source={ressources[selectedYear]} />
|
||||
<Markdown>{ressources[selectedYear]}</Markdown>
|
||||
{selectedYear !== '2019' && (
|
||||
<>
|
||||
<div
|
||||
|
@ -194,7 +194,7 @@ export default function Budget() {
|
|||
</tfoot>
|
||||
</RessourcesAllocationTable>
|
||||
</div>
|
||||
<Markdown source={ressourcesDescription} />
|
||||
<Markdown>{ressourcesDescription}</Markdown>
|
||||
</>
|
||||
)}
|
||||
<MoreInfosOnUs />
|
||||
|
|
|
@ -74,7 +74,7 @@ export default function ResultatsSimples() {
|
|||
</H3>
|
||||
|
||||
{r.rawNode.description && (
|
||||
<Markdown source={r.rawNode.description} />
|
||||
<Markdown>{r.rawNode.description}</Markdown>
|
||||
)}
|
||||
</FromTop>
|
||||
)
|
||||
|
@ -113,7 +113,7 @@ export default function ResultatsSimples() {
|
|||
</Intro>
|
||||
|
||||
{r.rawNode.description && (
|
||||
<Markdown source={r.rawNode.description} />
|
||||
<Markdown>{r.rawNode.description}</Markdown>
|
||||
)}
|
||||
<Intro>
|
||||
<RuleLink dottedName={r.dottedName}>
|
||||
|
|
|
@ -80,7 +80,7 @@ export default function ResultatsParFormulaire() {
|
|||
|
||||
{r.rawNode.description && (
|
||||
<div className="ui__ notice">
|
||||
<Markdown source={r.rawNode.description} />
|
||||
<Markdown>{r.rawNode.description}</Markdown>
|
||||
</div>
|
||||
)}
|
||||
<p className="ui__ lead" css="margin-bottom: 1rem;">
|
||||
|
@ -137,7 +137,7 @@ function DeclarationForm({ dottedName }: { dottedName: DottedName }) {
|
|||
{node.rawNode.résumé}
|
||||
{node.rawNode.description && (
|
||||
<ButtonHelp title={node.title} type="info">
|
||||
<Markdown source={node.rawNode.description} />
|
||||
<Markdown>{node.rawNode.description}</Markdown>
|
||||
</ButtonHelp>
|
||||
)}
|
||||
</small>
|
||||
|
|
|
@ -121,7 +121,7 @@ function FormulairePublicodes() {
|
|||
{type === 'groupe' ? (
|
||||
<Grid item xs={12}>
|
||||
{title && <HeaderComponent>{title}</HeaderComponent>}
|
||||
{description && <Markdown source={description} />}
|
||||
{description && <Markdown>{description}</Markdown>}
|
||||
</Grid>
|
||||
) : type === 'notification' ? (
|
||||
<WhenApplicable dottedName={dottedName as DottedName}>
|
||||
|
@ -148,13 +148,11 @@ function FormulairePublicodes() {
|
|||
`}
|
||||
>
|
||||
{' '}
|
||||
<Markdown
|
||||
source={
|
||||
typeof question !== 'string'
|
||||
? (engine.evaluate(question) as any).nodeValue
|
||||
: question
|
||||
}
|
||||
/>
|
||||
<Markdown>
|
||||
{typeof question !== 'string'
|
||||
? (engine.evaluate(question) as any).nodeValue
|
||||
: question}
|
||||
</Markdown>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@ -164,7 +162,7 @@ function FormulairePublicodes() {
|
|||
onChange={(value) => onChange(dottedName, value)}
|
||||
/>
|
||||
{question && type === undefined && description && (
|
||||
<Markdown source={description} />
|
||||
<Markdown>{description}</Markdown>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
|
|
|
@ -107,12 +107,10 @@ export default function Nouveautés() {
|
|||
</Sidebar>
|
||||
</Grid>
|
||||
<Grid item xs={12} lg={9}>
|
||||
<SimulationGoals>
|
||||
<MarkdownWithAnchorLinks
|
||||
source={data[selectedRelease].description}
|
||||
escapeHtml={false}
|
||||
renderers={{ text: TextRenderer }}
|
||||
/>
|
||||
<MainBlock>
|
||||
<MarkdownWithAnchorLinks renderers={{ text: TextRenderer }}>
|
||||
{data[selectedRelease].description}
|
||||
</MarkdownWithAnchorLinks>
|
||||
|
||||
<NavigationButtons>
|
||||
{selectedRelease + 1 < data.length ? (
|
||||
|
@ -128,7 +126,7 @@ export default function Nouveautés() {
|
|||
</Link>
|
||||
)}
|
||||
</NavigationButtons>
|
||||
</SimulationGoals>
|
||||
</MainBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<MoreInfosOnUs />
|
||||
|
@ -182,9 +180,7 @@ const Sidebar = styled.ul`
|
|||
}
|
||||
`
|
||||
|
||||
const SmallScreenSelect = styled.select``
|
||||
|
||||
const SimulationGoals = styled.div`
|
||||
const MainBlock = styled.div`
|
||||
flex: 1;
|
||||
|
||||
> h1:first-child,
|
||||
|
|
|
@ -69,7 +69,7 @@ export default function Activité({
|
|||
<H1>
|
||||
<Emoji emoji={activité.icônes} /> {activité.titre}
|
||||
</H1>
|
||||
<Markdown source={activité.explication} />
|
||||
<Markdown>{activité.explication}</Markdown>
|
||||
{activité.plateformes && (
|
||||
<SmallBody>
|
||||
<Emoji emoji={'📱 '} />
|
||||
|
|
|
@ -6031,6 +6031,11 @@ markdown-escapes@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
|
||||
integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
|
||||
|
||||
markdown-to-jsx@^7.1.5:
|
||||
version "7.1.5"
|
||||
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.5.tgz#caf72ad8a8c34a2bb692c4d17e44aabbe4eb19fd"
|
||||
integrity sha512-YQEMMMCX3PYOWtUAQu8Fmz5/sH09s17eyQnDubwaAo8sWmnRTT1og96EFv1vL59l4nWfmtF3L91pqkuheVqRlA==
|
||||
|
||||
matcher-collection@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29"
|
||||
|
@ -6798,7 +6803,11 @@ react-lifecycles-compat@^3.0.4:
|
|||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
<<<<<<< HEAD
|
||||
react-markdown@^4.1.0:
|
||||
=======
|
||||
react-markdown@^4.3.1:
|
||||
>>>>>>> d96c166a1 (Remplace react-markdown par markdown-to-jsx)
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.3.1.tgz#39f0633b94a027445b86c9811142d05381300f2f"
|
||||
integrity sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw==
|
||||
|
|
Loading…
Reference in New Issue