Hello guys!
I am building my own combined CMS and ecommerce platform in React to meet my personal requirements. I needed an ability to create, edit, remove and view page content in the application - just to be easier to edit content, when project is in production.
I want to share you my CMS approach and hear your opinions on this. In this posting I will show you, how the content is rendered - because I think that part is the more relevant.
There is two packages required in this approach and they are 'html-react-parser' and 'dompurify'.
Let's begin
First we have the component called Content. In my personal use case, Content component will get content ID as prop, so it can handle also logic to fetch content string from API.
In this example I am using HTML string, which we are rendering in the page. You may notice, that the htmlString has also some strange looking syntax, which starts with {{
and ends with }}
.
It is syntax for components, because we want to have an ability to render also components with this solution.
For example, in my use case I might want to rended component that displays newest products, or top-selling items, etc.
We will also sanitize the htmlString by using 'dompurify' package to prevent XSS attacks and other bad things.
import DOMPurify from "dompurify"
import parse from "html-react-parser"
const Content = () => {
const htmlString = `
<h1>Lorem ipsum</h1>
{{
ExampleComponent(
text: 'Lorem ipsum',
color: 'red'
)
}}
<p>Lorem ipsum dolor sit amet.</p>
<p>And the string continues ...</p>
`
const sanitizedHtml = DOMPurify.sanitize(htmlString)
...
}
Before moving on to parsing and rendering, we have to define what kind of component's are accepted to render. And don't forget to import components, if they are in other file!
const acceptedComponents = {
ExampleComponent,
OtherComponent
}
Okay, now we have sanitized our html string, defined accepted components and it is time move on to parsing and rendering the content.
...
function parseHtml(html) {
// We will split our HTML in to parts
const parts = html.split(/(\{{[^\}]+\}})/)
// Then we will map every part and return them correctly
return parts.map((part, index) => {
// In cases the part is surrounded with {{ }}, we will try to find a component, handle props, which are surrounded in ( )
if (part.startsWith('{{') && part.endsWith('}}')) {
const content = part.substring(2, part.length - 2).trim()
const [componentName, propString] = content.split(/\(|\)/)
// Tarkistetaan löytyykö komponentin nimi sallittujen listalta
const Component = acceptedComponents[componentName]
if (Component) {
const props = {}
// If we find some props
if (propString) {
const propPairs = propString.split(',')
// Let's map also props
propPairs.forEach(pair => {
const [propName, propValue] = pair.split(':').map(item => item.trim())
if (propName && propName.match(/^[A-Za-z]\w*$/) && propValue && propValue.match(/^".*"$/)) {
props[propName] = propValue.replace(/"/g, '')
}
})
}
// Return component with or without props and continue to next part
return <Component key={index} {...props} />
}
// To prevent errors, we want to also return message if component didn't found.
else {
return <p key={index}>Component {componentName} not found</p>
}
}
// If it is not component, we will parse HTML by using 'html-react-parser' package.
return parse(part)
})
}
// Component will return HTML parsed, showing HTML as HTMl and components as components, if found any.
return parseHtml(sanitizedHtml)
What do you guys think of this approach? 😊
Top comments (1)
Hey, nice article but you could use markdown to format the article better such as using heading, code higligher, bullets and other.