发布于 2026-01-06 3 阅读
0

Webflow 和 Next.js 集成概述 优势 劣势 将 Webflow 内容拉取到 Next.js 解析 Webflow 内容路由 自动化集成 更进一步 由 Mux 呈现的 DEV 全球展示挑战赛:展示你的项目!

集成 Webflow 和 Next.js

概述

好处

缺点

将 Webflow 内容导入 Next.js

解析 Webflow 内容

路由

自动化集成

更进一步

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

Webflow 基于 Next.js 架构图

⚠️更新:我们现已推出DesignSync.js!这是一个可导入 Webflow 网站的 Next.js 模板。它还能优化图片,并支持 Webflow 的交互和动画。如果您想快速构建精美的 Next.js 网站,那就赶紧来看看吧!

概述

Webflow是一款非常棒的无代码网站搭建工具,尤其适合设计师。它非常适合小型项目,但在尝试扩展规模时有时会出现一些问题:

  • 图片未针对视口或设备进行优化
  • 开发人员无法控制任何服务器端逻辑
  • 开发者无法直接操作 Webflow 的实时代码。
  • 构建 Web 应用程序很困难
  • ……可能还有很多我还没遇到过的情况。

本文将探讨如何使用WebflowNext.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网站,也请创建一个。

首先,我们来尝试让 Ne​​xt.js 项目的首页看起来像 Webflow 的首页。为此,我们需要获取 Webflow 的内容。我们可以使用Axios来实现这一点。此外,我们还需要一个名为Cheerio 的库来使用 Node 解析 HTML。

那么,让我们来安装这些:



yarn add axios
yarn add cheerio


Enter fullscreen mode Exit fullscreen mode

首先,我们来尝试渲染页面主体内容。打开你的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,
    },
  }
}


Enter fullscreen mode Exit fullscreen mode

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"


Enter fullscreen mode Exit fullscreen mode

现在运行程序yarn dev,你会看到内容显示出来,但很多样式都缺失了。这是因为我们没有加载内容<head>,我们只获取了文件<body>

解析 Webflow 内容

我们之前可以直接使用 React 的dangerouslySetInnerHTML方法将 body 内容放入其中。但这对于内容本身并不适用<head>。我们需要将这段 HTML 字符串转换成 JSX 可以理解的格式。为此,我们可以使用html-react-parser模块。



yarn add html-react-parser


Enter fullscreen mode Exit fullscreen mode

<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
  },
}


Enter fullscreen mode Exit fullscreen mode

然后,在我们的组件中,我们可以解析内容并将其转换为 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}} />
    </>
  )
}

...


Enter fullscreen mode Exit fullscreen mode

现在你应该能在 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


Enter fullscreen mode Exit fullscreen mode

现在我们需要添加一个动态路径来捕获所有其他路由。这样我们就可以渲染所有 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>
      )
    }
  }

}

...



Enter fullscreen mode Exit fullscreen mode

我不太确定为什么这样能行,但它确实有效。如果有人有更优雅的解决方案,请在评论区告诉我。

自动化集成

如果集成不是自动化的,那就不能称之为真正的应用内集成 (ADI)。我们真正想要的是,每次 Webflow 设计更改时,Next.js 网站都能自动更新。

NetlifyVercel都是托管 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