集成 Webflow 和 Next.js
概述
好处
缺点
将 Webflow 内容导入 Next.js
解析 Webflow 内容
路由
自动化集成
更进一步
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
⚠️更新:我们现已推出DesignSync.js!这是一个可导入 Webflow 网站的 Next.js 模板。它还能优化图片,并支持 Webflow 的交互和动画。如果您想快速构建精美的 Next.js 网站,那就赶紧来看看吧!
概述
Webflow是一款非常棒的无代码网站搭建工具,尤其适合设计师。它非常适合小型项目,但在尝试扩展规模时有时会出现一些问题:
- 图片未针对视口或设备进行优化
- 开发人员无法控制任何服务器端逻辑
- 开发者无法直接操作 Webflow 的实时代码。
- 构建 Web 应用程序很困难
- ……可能还有很多我还没遇到过的情况。
本文将探讨如何使用Webflow和Next.js实现自动化设计集成 (ADI)。如果您读过我关于ADI 模式的文章,就会知道我们这里要实现的是“嵌入模式”。这意味着我们将设计嵌入到另一个平台(即核心平台)中,这样设计就可以利用核心平台的一些功能,而这些功能可能是设计平台本身所不具备的。
好处
通过将 Webflow 与 Next.js 结合使用,我们基本上可以兼得两者的优势。设计师可以完全掌控 Webflow 中的设计,而开发者则可以完全掌控 Next.js 中的代码。开发者仍然可以在 Next.js 中创建应用所需的任何页面,或者将组件嵌入到来自 Webflow 站点的页面代码中。
这种方法对于内容来自多个来源的混合型网站也非常适用。设计师仍然可以在 Webflow 中进行设计,而开发人员可以在 Next.js 中获取 WordPress、Shopify 或 API 数据,并将内容拼接到 Webflow 模板中。
这两项服务对于小型使用场景都是免费的。因此,如果您的需求不大,您可以免费拥有一个功能强大的网站。
最后,我们可以通过一些调整来提升性能和搜索引擎优化效果。稍后我们会详细介绍。
缺点
目前我发现的唯一真正缺点是 Webflow 的 JS 在后续导航中不起作用。因此,交互和动画可能无法始终正常工作。
这可以通过两种方式解决:一是添加您自己的可在 React 中运行的 JS 代码;二是完全避免交互,并使用库来处理此类事情。
将 Webflow 内容导入 Next.js
本教程假设您已经对Node.js、Next.js 和 Webflow 有一定的了解。我使用Yarn作为包管理器,但npm也完全可以。
首先,如果您还没有在电脑上创建 Next.js 应用,请创建一个。如果您还没有Webflow网站,也请创建一个。
首先,我们来尝试让 Next.js 项目的首页看起来像 Webflow 的首页。为此,我们需要获取 Webflow 的内容。我们可以使用Axios来实现这一点。此外,我们还需要一个名为Cheerio 的库来使用 Node 解析 HTML。
那么,让我们来安装这些:
yarn add axios
yarn add cheerio
首先,我们来尝试渲染页面主体内容。打开你的pages/index.js文件,并将内容替换为以下内容:
// ./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,
},
}
}
Webflow URL 是通过环境变量引用的。要将其添加到本地环境中,请在项目根目录下创建一个名为 `webflow.xml` 的文件.env.local,并添加以下内容:
# Replace the URL with your own Webflow site; no trailing slash
WEBFLOW_URL = "https://business-starter-template.webflow.io"
现在运行程序yarn dev,你会看到内容显示出来,但很多样式都缺失了。这是因为我们没有加载内容<head>,我们只获取了文件<body>。
解析 Webflow 内容
我们之前可以直接使用 React 的dangerouslySetInnerHTML方法将 body 内容放入其中。但这对于内容本身并不适用<head>。我们需要将这段 HTML 字符串转换成 JSX 可以理解的格式。为此,我们可以使用html-react-parser模块。
yarn add html-react-parser
<body>就在我们用 Cheerio获取内容的地方下面,我们也会拿到这些<head>东西,并把它们作为道具一起寄出去。
// ./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
},
}
然后,在我们的组件中,我们可以解析内容并将其转换为 JSX,然后使用next/head<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}} />
</>
)
}
...
现在你应该能在 Next.js 应用中看到 Webflow 网站的样式化首页了。你可能需要删除默认pages/_app.js文件,因为它可能引入了一个全局样式表,而这个样式表与 Webflow 的样式表冲突。
路由
目前,Next.js 并没有对页面进行任何 Webflow 无法实现的操作。我们基本上只是原封不动地展示一个 Webflow 页面。Next.js 的一个优势是客户端路由,它可以让你的网站在内部导航方面拥有类似应用程序的速度。让我们把这个功能添加到我们的 Next.js / Webflow 项目中。
由于我们已经在索引文件中实现了所需的逻辑,可以直接复用。但是我们需要一个`getStaticPaths`函数来告诉 Next.js 所有可能的路径。我们可以使用`sitemap-links`模块从 Webflow 站点的站点地图中读取这些路径。让我们来安装它:
yarn add sitemap-links
现在我们需要添加一个动态路径来捕获所有其他路由。这样我们就可以渲染所有 Webflow 页面,而不仅仅是首页。我们可以通过在pages名为 . 的目录中添加一个 aa 文件来实现这一点[...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`,
}
}
```
Now we'll add some extra logic to the component in `index.js` to parse and transform regular HTML links into Next.js links.
```jsx
// ./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)}
</>
)
}
...
```
This might look like a lot, but it's basically just adding some parsing options to find and replace any `<a>` links with the Next.js `<Link>`.
We'll also need to change the `getStaticProps` function to determine which Webflow page to fetch based on the URL path, rather than just fetching the homepage.
```jsx
// ./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
},
}
}
```
Now that your Next.js app can parse and transform all your Webflow links to Next.js links, it should be transitioning and rendering pages much quicker than a vanilla Webflow site.
# Fixing Fonts
As mentioned in the drawbacks section, some JS doesn't work. This is a problem if your template is using Google Fonts. If you are, they likely aren't loading in properly because Google Fonts uses a little JavaScript snippet to initiate.
To do this, you can just delay the webfont a little bit by transforming it in the `pages/index.js` file:
```jsx
// ./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>
)
}
}
}
...
我不太确定为什么这样能行,但它确实有效。如果有人有更优雅的解决方案,请在评论区告诉我。
自动化集成
如果集成不是自动化的,那就不能称之为真正的应用内集成 (ADI)。我们真正想要的是,每次 Webflow 设计更改时,Next.js 网站都能自动更新。
Netlify和Vercel都是托管 Next.js 网站的优秀平台。本教程将使用 Vercel 来托管我们的 Next.js 项目。如果您尚未将Next.js 项目部署到 Vercel,请先进行部署。请记住将 `<webflow-site-url>` 设置WEBFLOW_URL为您的 Webflow 网站 URL,无需包含末尾的斜杠。
在 Vercel 控制面板的“git”部分,您可以创建一个部署钩子。复制此 URL。
然后,在 Webflow 网站的控制面板中,在“集成”选项卡中创建一个 Webhook URL。选择“网站发布”作为触发类型,并将从 Vercel 获取的 URL 粘贴为“Webhook URL”。
现在,每当您的 Webflow 网站发布任何更改时,它都会向 Vercel 发送通知,以重新构建 Next.js 项目。
更进一步
这是该项目的最终源代码链接。这只是该集成的一个基本实现。以下是一些关于如何进一步完善它的想法:
- 使用 Next.js 图片模块优化 Webflow 图片
- 使用 Webflow 页面路由设置 Next.js 站点地图
- 如何让在 Webflow 控制面板中创建的重定向在 Next.js 中生效
- 如何在 Next.js 中实现 Webflow 的交互和动画效果
- 页面导航之间始终显示页眉/页脚
- 优化代码以提升 Google Lighthouse 和 Core Web Vitals 指标
如果您希望我介绍这些新增功能或其他任何内容,请在评论区留言,我会发布后续文章。我也很想知道您正在开发什么项目,以及这些功能可能如何帮助您!
文章来源:https://dev.to/kennedyrose/integrating-webflow-and-next-js-39kk
