21
loading...
This website collects cookies to deliver better user experience
yarn add axios
yarn add cheerio
pages/index.js
file and replace the contents with this:// ./pages/index.js
export default function Home(props) {
return <div dangerouslySetInnerHTML={{ __html: props.bodyContent }} />
}
export async function getStaticProps(ctx) {
// Import modules in here that aren't needed in the component
const cheerio = await import(`cheerio`)
const axios = (await import(`axios`)).default
// Fetch HTML
let res = await axios(process.env.WEBFLOW_URL).catch((err) => {
console.error(err)
})
const html = res.data
// Parse HTML with Cheerio
const $ = cheerio.load(html)
const bodyContent = $(`body`).html()
// Send HTML to component via props
return {
props: {
bodyContent,
},
}
}
.env.local
and add the following contents:# Replace the URL with your own Webflow site; no trailing slash
WEBFLOW_URL = "https://business-starter-template.webflow.io"
yarn dev
, you'll see the content displays, but a lot of styles aren't there. That's because we didn't load the <head>
content, we only got the <body>
.<head>
content. We'll need to actually convert that string of HTML into something that JSX can understand. For this we can use the html-react-parser module.yarn add html-react-parser
<body>
content with Cheerio, we'll get the <head>
stuff too and also send that along as props.// ./pages/index.js
...
// Parse HTML with Cheerio
const $ = cheerio.load(html)
const bodyContent = $(`body`).html()
const headContent = $(`head`).html()
// Send HTML to component via props
return {
props: {
bodyContent,
headContent
},
}
<head>
contents to JSX and add it to the document with next/head.// ./pages/index.js
import Head from 'next/head'
import parseHtml from 'html-react-parser'
export default function Home(props) {
return (
<>
<Head>
{parseHtml(props.headContent)}
</Head>
<div dangerouslySetInnerHTML={{__html: props.bodyContent}} />
</>
)
}
...
pages/_app.js
file, as it's probably pulling in a global style sheet that is/will conflict with the Webflow one.yarn add sitemap-links
pages
directory called [...path].js
.// ./pages/[...path].js
import GetSitemapLinks from 'sitemap-links'
import DynamicPath, { getStaticProps } from './index'
export default DynamicPath
export { getStaticProps }
export async function getStaticPaths() {
// Fetch links from Webflow sitemap
const sitemapLink = process.env.WEBFLOW_URL + `/sitemap.xml`
const links = await GetSitemapLinks(sitemapLink).catch((err) => {
console.error(err)
})
// Extract paths from absolute links
const paths = []
for (let link of links) {
let url = new URL(link)
const path = url.pathname.replace(`/`, ``).split(`/`)
if (!path.length || !path[0]) continue
paths.push({
params: { path },
})
}
return {
paths: paths,
fallback: `blocking`,
}
}
index.js
to parse and transform regular HTML links into Next.js links.// ./pages/index.js
import Head from 'next/head'
import Link from 'next/link'
import parseHtml, { domToReact } from 'html-react-parser'
import get from 'lodash/get'
// Determines if URL is internal or external
function isUrlInternal(link){
if(
!link ||
link.indexOf(`https:`) === 0 ||
link.indexOf(`#`) === 0 ||
link.indexOf(`http`) === 0 ||
link.indexOf(`://`) === 0
){
return false
}
return true
}
// Replaces DOM nodes with React components
function replace(node){
const attribs = node.attribs || {}
// Replace links with Next links
if(node.name === `a` && isUrlInternal(attribs.href)){
const { href, ...props } = attribs
if(props.class){
props.className = props.class
delete props.class
}
return (
<Link href={href}>
<a {...props}>
{!!node.children && !!node.children.length &&
domToReact(node.children, parseOptions)
}
</a>
</Link>
)
}
}
const parseOptions = { replace }
export default function Home(props) {
return (
<>
<Head>
{parseHtml(props.headContent)}
</Head>
{parseHtml(props.bodyContent, parseOptions)}
</>
)
}
...
<a>
links with the Next.js <Link>
.getStaticProps
function to determine which Webflow page to fetch based on the URL path, rather than just fetching the homepage.// ./pages/index.js
...
export async function getStaticProps(ctx) {
// Import modules in here that aren't needed in the component
const cheerio = await import(`cheerio`)
const axios = (await import(`axios`)).default
// Use path to determine Webflow path
let url = get(ctx, `params.path`, [])
url = url.join(`/`)
if(url.charAt(0) !== `/`){
url = `/${url}`
}
const fetchUrl = process.env.WEBFLOW_URL + url
// Fetch HTML
let res = await axios(fetchUrl)
.catch(err => {
console.error(err)
})
const html = res.data
// Parse HTML with Cheerio
const $ = cheerio.load(html)
const bodyContent = $(`body`).html()
const headContent = $(`head`).html()
// Send HTML to component via props
return {
props: {
bodyContent,
headContent
},
}
}
pages/index.js
file:// ./pages/index.js
...
// Replaces DOM nodes with React components
function replace(node){
const attribs = node.attribs || {}
// Replace links with Next links
if(node.name === `a` && isUrlInternal(attribs.href)){
const { href, ...props } = attribs
if(props.class){
props.className = props.class
delete props.class
}
return (
<Link href={href}>
<a {...props}>
{!!node.children && !!node.children.length &&
domToReact(node.children, parseOptions)
}
</a>
</Link>
)
}
// Make Google Fonts scripts work
if(node.name === `script`){
let content = get(node, `children.0.data`, ``)
if(content && content.trim().indexOf(`WebFont.load(`) === 0){
content = `setTimeout(function(){${content}}, 1)`
return (
<script {...attribs} dangerouslySetInnerHTML={{__html: content}}></script>
)
}
}
}
...