如何建立一个前端的静态WordPress网站

近年来,我们一直在探索很多流行的堆栈和框架。它们都带来了性能升级和易用性,但我们已经很久没有谈论现代网络的 OG 了。当然,我说的是 WordPress。

尽管WordPress 为 Internet 上所有网站的 42%提供支持,但有时感觉 WordPress 的发展不足以与 Next.js、Vue.js、Gatsby 等新框架竞争。

如果我告诉您可以继续使用 WordPress,同时利用 React 的强大功能来构建您的前端呢?好吧,多亏了 Frontity,可以快速构建一个最先进的 WordPress 网站。

让我们探索这个新框架,看看我们如何利用它来构建电子商务网站。

什么是前沿?

Frontity 标志

Frontity是一个基于 React 的开源框架。它使用您的 WordPress 站点作为无头 CMS并将其呈现在 React 框架中。它使您能够快速构建一个快速的无头 WordPress 静态网站。

它通过编译和构建 HTML 页面并在有客户端请求时为它们提供服务,从而像静态站点生成器一样工作。 React 的无服务器预渲染处理页面的动态内容,就像任何其他静态站点一样。

Frontity 管理捆绑、转译、路由、服务器渲染、管理状态、管理 CSS、从 WordPress 检索数据等。它是一个零设置框架,支持 TypeScript 以及Emotion用于 JavaScript 中的 CSS 样式。它还支持具有相同代码库的 GoogleAMP。

该框架还通过其名为 Frontity Connect 的状态管理器提供应用程序状态管理。包含您的包公开的所有状态的 JavaScript 对象与设置合并。这样,包可以访问其他包公开的状态。

开发现代 WordPress 网站现在轻而易举。对于像我这样不是开发人员的人来说,这让我的生活更轻松。

Frontity 带来的功能类似于您从另一个静态站点生成器获得的功能。

但是,让它与 WordPress 搭配起来不费吹灰之力的原因在于它的速度有多快。严重地。由于它是服务器端渲染的,所以一切都很快并且几乎可以立即加载。

它是如何工作的?

Frontity 使用 WordPress RESTAPI从您的 WordPress 站点(PHP 服务器)获取数据并将其呈现在您的 React 前端(Node.js 服务器)中。 Frontity 然后以 HTML 或AMP呈现页面。 Frontity 可以托管在常规的 Node.js 服务器或无服务器服务(如 AWS、Netlify 或 Vercel)中。

这很好,但他们的街头信誉呢?好吧,Frontity 受到 TikTok 的信任,可以建立他们的创作者门户网站、CNBC Africa和Forbes Africa等等。

和盖茨比相比如何?

Gatsby 与 WordPress 的 Frontity 相比

Gatsby 还提供了一个前端来使用 WordPress 实例作为无头 CMS 来构建静态网站。因此,让我们探索 Frontity 与它的比较。

首先,这两个框架都是基于 React 的。

由于静态页面,Gatsby 和 Frontity 都带来了更快的初始页面加载时间。这些框架还可以开箱即用地处理应用程序路由,因此我们不必进行设置。

这两个框架还受益于代码拆分,这可以优化它们以在 Lighthouse 中获得更好的性能得分。

然而,正如我们之前看到的,Frontity 是一个随时可用的框架,一切都为我们设置好了。它对开发人员友好(或者,在我的情况下,对初学者友好),不需要复杂的配置,API 查询等工具是预先配置的。

Frontity 还通过其状态管理器提供数据,从而消除了处理 GraphQL 的需要。

现在说够了;是时候深入研究它了。让我们自己看看这个基于 React 的框架能做什么!

教程:使用 Frontity 构建无头电子商务 WordPress 网站

对于本教程,让我们使用 Snipcart 构建一个简单的电子商务网站来销售辣酱。

先决条件

  • AWordPress实例托管

  • JavaScript 知识

  • Snipcart 帐户(永久免费测试)

第 1 步:在 WordPress 中创建我们的页面

我们需要做的第一步是在 WordPress 中创建我们的页面。我们将创建一个包含两个页面(不包括我们的产品页面)的简单电子商务网站。第一个是我们的主页,另一个是关于我们的页面。

要创建它们,只需进入 WordPress 管理菜单中的Pages并单击“添加新”以创建我们的页面。我们的主页将命名为“Hottest Hot Sauce Sauce”,关于我们的页面将命名为“About Us”。完成后,确保进入Settings/Reading并选择“静态页面”并从下拉菜单中选择主页。

WordPress仪表板面板阅读设置静态主页

设置时,请确保激活Settings/Permalinks中的 Post name 永久链接,以确保 Frontity 能够正常运行。

第 2 步:在 WordPress 中创建产品

现在我们已经创建了一个 WordPress 实例并运行了我们的页面,让我们创建我们的产品。

要创建我们的产品,我们首先需要安装Advanced Custom Fields 插件。一旦安装并激活。让我们创建一个包含以下内容的新字段组。

创建高级自定义字段组

之后,从 WordPress 仪表板菜单中选择“帖子”,然后单击“添加新”。

给它一个名字,然后选择在我们刚刚创建的自定义字段中输入数据。

在 WordPress 中使用自定义字段创建产品

我们还需要将ACF 添加到 REST API插件,以便稍后在 Frontity 中获取我们的高级自定义字段。

第三步:创建 Frontity 项目

现在我们已经在 WordPress 中设置了我们需要的一切,是时候深入研究 Frontity 了。

我们需要创建我们的项目。为此,请运行以下命令:

npx frontity create my-first-frontity-project 

Frontity CLI 将提示您选择一个主题。对于这个演示,我们选择@frontity/twentytwenty-theme

完成后,您将拥有开始开发所需的一切,我们将为下一步做好准备。

第 4 步:将 Frontity 连接到 WordPress REST API

要将我们的数据放在 Frontity 中,我们需要连接到 WordPress REST API。为此,请打开frontity.settings.js并将YOUR-WORDPRESS_SITE.com(在const settings中)替换为我们 WordPress 站点的 URL。这将告诉 Frontity 在哪里可以找到我们的网站内容。

在同一个常量中,我们将更改"title""description"的值。这些将呈现在我们网站的标题中。

我们还需要连接 REST API。为此,只需将YOUR-WORDPRESS_SITE.com/wp-json替换为您的 WordPress URL,后跟/wp-json

请注意,此路线可能会根据您设置主页的方式以及您使用的是WordPress.org还是WordPress.com而改变。

我们还将配置菜单名称及其路径、站点标题和描述。"title""description"我们将用于我们的站点元数据。

const settings = { "name": "wordpress-frontity-snipcart", "state": { "frontity": { "url": "<https://snipcart-hotsauce-shop.azurewebsites.net/>", "title": "Snipcart Hot Sauce Shop", "description": "The Hottest Hot Sauce Shop!" } }, "packages": [ { "name": "@frontity/twentytwenty-theme", "state": { "theme": { "menu": [ [ "Shop", "/" ], [ "About Us", "/about-us/" ] ], "featured": { "showOnList": false, "showOnPost": false } } } }, { "name": "@frontity/wp-source", "state": { "source": { "api": "<https://snipcart-hotsauce-shop.azurewebsites.net/wp-json>" } } }, "@frontity/tiny-router", "@frontity/html2react" ] }; export default settings; 

我们还需要将 connect Frontity 添加到自定义字段数据并获取我们的产品信息。为此,让我们将packages/twentytwenty-theme/src/index.js的内容替换为以下内容:

import Theme from "./components"; import image from "@frontity/html2react/processors/image"; import link from "@frontity/html2react/processors/link"; // Custom handler for ACF options const acfOptionsHandler = { pattern: "acf-options-page", func: async ({ route, state, libraries }) => { // 1. Get ACF option page from REST API. const response = await libraries.source.api.get({ endpoint: `/acf/v3/posts` }); const option = await response.json(); // 2. Add data to `source`. const data = state.source.get(route); Object.assign(data, { ...option, isAcfOptionsPage: true }); } }; const twentyTwentyTheme = { name: "@frontity/twentytwenty-theme", roots: { /** * In Frontity, any package can add React components to the site. * We use roots for that, scoped to the `theme` namespace. */ theme: Theme, }, state: { /** * State is where the packages store their default settings and other * relevant state. It is scoped to the `theme` namespace. */ theme: { colors: { gray: { base: "#6D6D6D", light: "#DCD7CA", lighter: "#F5EFE0", }, primary: "#0aa7f5", headerBg: "#ffffff", footerBg: "#ffffff", bodyBg: "#f1f2f4", }, // Whether to show the search button in page header showCartInHeader: true, // Menu links to display in the header menu: [], // State for the menu on mobile isMobileMenuOpen: false, // State for the search modal on mobile isSearchModalOpen: false, // Whether to show all post content or only excerpt (summary) in archive view showAllContentOnArchive: false, // Settings for the featured media (image or video) featuredMedia: { // Whether to show it on archive view showOnArchive: true, // Whether to show it on post showOnPost: true, }, // Whether to auto-fetch links on a page. Values can be "no" | "all" | "in-view" | "hover" autoPrefetch: "in-view", /** * At the moment, we only include the ascii characters of Inter font. * Values can be "us-ascii" | "latin" | "all". */ fontSets: "all", }, }, /** * Actions are functions that modify the state or deal with other parts of * Frontity like libraries. */ actions: { theme: { beforeSSR: async ({ state, actions }) => { // This will make Frontity wait until the ACF options // page has been fetched and it is available // using state.source.get("acf-options-page"). await actions.source.fetch("posts"); }, openMobileMenu: ({ state }) => { state.theme.isMobileMenuOpen = true; }, closeMobileMenu: ({ state }) => { state.theme.isMobileMenuOpen = false; }, openSearchModal: ({ state }) => { state.theme.isSearchModalOpen = true; }, closeSearchModal: ({ state }) => { state.theme.isSearchModalOpen = false; }, }, }, libraries: { source: { handlers: [acfOptionsHandler] }, html2react: { /** * Add a processor to `html2react` so it processes the `<img>` tags * and internal link inside the content HTML. * You can add your own processors too. */ processors: [image, link], }, }, }; export default twentyTwentyTheme; 

通过构建我们的项目,我们应该能够看到我们的 WordPress 内容。在终端中运行构建命令:

npx frontify dev 

构建完成后,您的 Web 浏览器应该会自动启动本地主机。如果没有,只需转到http://localhost:3000。

第 5 步:安装 Snipcart

packages/twentytwenty-theme/src/components/index.js<head>元素中添加 Snipcart 预连接提示和样式表:

<Head> //.. <link rel="preconnect" href="<https://app.snipcart.com>"/> <link rel="preconnect" href="<https://cdn.snipcart.com>"/> <link rel="stylesheet" href="<https://cdn.snipcart.com/themes/v3.2.2/default/snipcart.css>" /> </Head> 

在同一个文件中,通过将这两行粘贴到<Footer />元素下,将 Snipcart 添加到我们的站点:

<script async src="<https://cdn.snipcart.com/themes/v3.2.2/default/snipcart.js>"></script> <div hidden id="snipcart" data-api-key="YOUR_PUBLIC_API_KEY"></div> 

提醒将YOUR_PUBLIC_API_KEY替换为您的公共 API 密钥。您可以在测试模式下的 Snipcart Dashboard 中找到它。

Snipcart 公共 API

第 6 步:创建 Snipcart 购买按钮和产品卡组件

现在已经安装了 Snipcart,是时候将我们之前创建的产品自定义字段与 Snipcart 购买按钮连接起来了。同时,这将使 Frontity 能够显示我们在 WordPress 中输入的产品信息。

为此,我们将在packages/twentytwenty-theme/src/components中创建一个名为ecommerce的新文件夹,并在其中创建两个新文件。一个名称为product-card.js,另一个名称为snipcart-button.js

product-card.js中,让我们创建一个名为ProductCard的新组件,它将接收 WordPress 帖子(我们的产品信息)作为道具。该组件还将调用SnipcartButton组件将在之后创建。为此,请将以下内容添加到文件中:

import SnipcartButton from "./snipcart-button"; const ProductCard = ({post}) => { const product = { name: post.acf.product_name, id: post.id, price: post.acf?.price, image: post.acf?.image, description: post.acf?.description } return ( <article> <img src={post.acf.image} /> <div> {post.acf.description} </div> <div> <strong> ${post.acf.price} </strong> </div> <SnipcartButton product={product} /> </article> ) } export default ProductCard; 

现在让我们通过在snipcart-button.js中添加以下内容来创建我们的SnipcartButton组件:

const SnipcartButton = ({product}) => { return ( <button className="snipcart-add-item" data-item-name={product.name} data-item-price={product.price} data-item-image={product.image} data-item-id={product.id} data-item-description={product.description}>Add to cart </button> ) } export default SnipcartButton; 

第 7 步:将我们的组件添加到我们的页面

现在我们已经在最后一步创建了我们的主页和产品页面。为此,让我们将packages/twentytwenty-theme/src/components/post/post.js的内容替换为以下内容:

import { styled, connect } from "frontity"; import { useEffect } from "react"; import FeaturedMedia from "./featured-media"; import { EntryContent, Post as _Post, PostHeader, PostInner, PostTitle, PostCaption, SectionContainer, } from "./post-item"; import ProductCard from "./../ecommerce/product-card"; /** * The Post component that the TwentyTwenty theme uses for rendering any kind of * "post type" (posts, pages, attachments, etc.). * * It doesn't receive any prop but the Frontity store, which it receives from * {@link connect}. The current Frontity state is used to know which post type * should be rendered. * * @param props - The Frontity store (state, actions, and libraries). * * @example * * <Switch> * <Post when={data.isPostType} /> * </Switch> * * * @returns The {@link Post} element rendered. */ const Post = ({ state, actions, libraries }) => { // Get information about the current URL. const data = state.source.get(state.router.link); // Get the data of the post. const post = state.source[data.type][data.id]; // Get the html2react component. const Html2React = libraries.html2react.Component; const isProduct = (post) => { return !!post.acf.price; } /** * Once the post has loaded in the DOM, prefetch both the * home posts and the list component so if the user visits * the home page, everything is ready and it loads instantly. */ useEffect(() => { actions.source.fetch("/"); }, [actions.source]); // Load the post, but only if the data is ready. return data.isReady ? ( <PostArticle> <Header> <SectionContainer> {/* If the post has categories, render the categories */} <PostTitle as="h1" className="heading-size-1" dangerouslySetInnerHTML={{ __html: post.title.rendered }} /> {/* If the post has a caption (like attachments), render it */} {post.caption && ( <PostCaption dangerouslySetInnerHTML={{ __html: post.caption.rendered }} /> )} </SectionContainer> </Header> {/* * If the want to show featured media in the * list of featured posts, we render the media. */} {state.theme.featuredMedia.showOnPost && ( <FeaturedImage id={post.featured_media} isSinglePost={true} /> )} {/* If the post has a description (like attachments), we render it */} {post.description && ( <PostInner size="thin"> <EntryContent dangerouslySetInnerHTML={{ __html: post.description.rendered }} /> </PostInner> )} {/* If the post has content, we render it */} {post.content && isProduct(post) && ( <PostInner size="thin"> <EntryContent> <ProductCard post={post} /> </EntryContent> </PostInner> )} {post.content && !isProduct(post) && ( <PostInner size="thin"> <EntryContent> <Html2React html={post.content.rendered} /> </EntryContent> {/* If the post has tags, render it */} {post.tags && <PostTags tags={tags} />} </PostInner> )} </PostArticle> ) : null; }; export default connect(Post); const Header = styled(PostHeader)` background-color: #fff; margin: 0; padding: 4rem 0; @media (min-width: 700px) { padding: 8rem 0; } `; const PostArticle = styled(_Post)` padding-top: 0 !important; `; const FeaturedImage = styled(FeaturedMedia)` margin-top: 0 !important; position: relative; > div { position: relative; } &:before { background: #fff; content: ""; display: block; position: absolute; bottom: 50%; left: 0; right: 0; top: 0; } `; 

如您所见,我们已经导入了ProductCard组件并添加了一个小帮助函数来帮助我们识别帖子是否具有产品属性。我们使用此功能来显示产品卡片或常规 WordPress 帖子。

我们还需要更改packages/twentytwenty-theme/src/components/post/post-item.js的内容以在主页上显示我们的产品卡片。

import { connect, styled } from "frontity"; import Link from "../link"; import FeaturedMedia from "./featured-media"; import ProductCard from "./../ecommerce/product-card"; /** * Article Component. * * It renders the preview of a blog post. Each blog post contains: * - Title: clickable title of the post. * - FeaturedMedia: the featured image/video of the post. * * @param props.state - The Frontity state. * @param props.libraries - The Frontity libraries. * @param props.item - The post entity. * @param props.showExcerpt - If the post excerpt should be rendered. * @param props.showMedia - If the featured media should be rendered. * * @returns React element. */ const PostItem = ({ state, libraries, item, showMedia = true, }) => { const post = state.source[item.type][item.id]; const { Component: Html2React } = libraries.html2react; return ( <Post> <PostHeader> <SectionContainer> {/* The clickable heading for the post */} <PostLink link={item.link}> <PostItemTitle className="heading-size-1" dangerouslySetInnerHTML={{ __html: item.title.rendered }} /> </PostLink> </SectionContainer> </PostHeader> {/* * If the want to show featured media in the * list of featured posts, we render the media. */} {state.theme.featuredMedia.showOnArchive && showMedia && ( <FeaturedMedia id={item.featured_media} /> )} {post && post.content && ( <PostInner size="thin"> <EntryContent> <ProductCard post={post} /> </EntryContent> </PostInner> )} </Post> ); }; // Connect the Item to gain access to `state` as a prop export default connect(PostItem); // All styles :) export const Post = styled.article` &:first-of-type { padding: 4rem 0 0; } @media (min-width: 700px) { &:first-of-type { padding: 8rem 0 0; } } `; export const PostHeader = styled.header` text-align: center; `; // Header sizes bases on style.css const maxWidths = { thin: "58rem", small: "80rem", medium: "100rem", }; /** * Return a CSS size depending on the value of the `size` prop received (see * {@link maxWidths}). * * @param props - Component props, including a `size` one. * @returns Size in CSS units. */ const getMaxWidth = (props) => maxWidths[props.size] || maxWidths["medium"]; export const SectionContainer = styled.div` margin-left: auto; margin-right: auto; width: calc(100% - 4rem); max-width: ${getMaxWidth}; @media (min-width: 700px) { width: calc(100% - 8rem); } `; export const PostItemTitle = styled.h2` margin: 0; @media (min-width: 700px) { font-size: 6.4rem; } `; export const PostTitle = styled.h1` margin: 0; `; export const PostCaption = styled(SectionContainer)` /* .section-inner.max-percentage */ margin-left: auto; margin-right: auto; max-width: ${getMaxWidth({ size: "small" })}; width: 100%; /* .singular .intro-text */ margin-top: 2rem; font-size: 2rem; letter-spacing: -0.0315em; line-height: 1.4; @media (min-width: 700px) { margin-top: 2.5rem; font-size: 2.6rem; } @media (min-width: 1000px) { font-size: 2.8rem; } @media (min-width: 1220px) { font-size: 3.2rem; letter-spacing: -0.03125em; line-height: 1.375; } `; const PostLink = styled(Link)` color: #000000; text-decoration: none; display: inline-block; &:hover { text-decoration: underline; } `; export const PostInner = styled(SectionContainer)` padding-top: 5rem; @media (min-width: 700px) { padding-top: 8rem; } `; export const EntryContent = styled.div` line-height: 1.5; max-width: 58rem; font-family: "Hoefler Text", Garamond, "Times New Roman", serif; letter-spacing: normal; @media (min-width: 700px) { font-size: 2.1rem; } > *:first-of-type { margin-top: 0; } figure { margin: 2em 0; max-width: 100%; } h1, h2, h3, h4, h5, h6, cite, figcaption, table, address, .wp-caption-text, .wp-block-file { font-family: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, sans-serif; } h1, h2, h3, h4, h5, h6 { margin: 3.5rem auto 2rem; } @media (min-width: 700px) { h1, h2, h3 { margin: 6rem auto 3rem; } h4, h5, h6 { margin: 4.5rem auto 2.5rem; } } `; 

现在您应该可以直接从主页查看您的产品和“添加到购物车”按钮。

第 8 步:添加查看购物车按钮

现在让我们在标题中添加一个按钮来查看购物车。

安装了 Frontity 主题后,我们有两个视图;移动和桌面。我们将利用预定义的搜索组件样式来创建我们的按钮。

首先,让我们在packages/twentytwenty-theme/src/components/中创建一个cart-button.js文件,其中包含以下内容:

import { connect, styled } from "frontity"; import { BaseToggle, ToggleWrapper, } from "./navigation/nav-toggle"; const CartButton = ({ state, actions }) => { return ( <HeaderToggle> <ToggleWrapper> <BaseToggle className="snipcart-checkout"> 🛒 </BaseToggle> </ToggleWrapper> </HeaderToggle> ); }; export default connect(CartButton); const HeaderToggle = styled.div` display: none; @media (min-width: 1000px) { display: flex; flex-shrink: 0; margin-right: -3rem; margin-left: 3rem; } @media (min-width: 1220px) { margin-right: -4rem; margin-left: 4rem; } `; 

然后,我们将通过创建一个包含以下代码的cart-button.jspackages/twentytwenty-theme/src/components/mobile中添加我们的移动购物车按钮:

import { connect, styled } from "frontity"; import { CartToggle, ToggleWrapper, } from "../navigation/nav-toggle"; const MobileCartButton = ({ state, actions }) => { return ( <ToggleWrapper> <ShowMobile> <BaseToggle className="snipcart-checkout"> 🛒 </BaseToggle> </ShowMobile> </ToggleWrapper> ); }; export const ShowMobile = styled.div` display: inline-block; @media (min-width: 1000px) { display: none; } `; export default connect(MobileCartButton); 

创建这些组件后,我们需要在标题组件中定义它们:

packages/src/components/header.js import { connect, Global, Head, styled } from "frontity"; //.. import CartButton from "./cart-button"; import MobileCartButton from "./mobile/cart-button"; return ( <PageHeader bg={headerBg} id="site-header"> <HeaderInner> <TitleWrapper> {/* Cart button on mobile */} <MobileCartButton /> {/* Heading and Description of the site */} <TitleGroup> <SiteTitle> <StyledLink link="/">{title}</StyledLink> </SiteTitle> <SiteDescription>{description}</SiteDescription> </TitleGroup> {/* Mobile menu button and modal */} <MobileMenuButton /> <MobileMenuModal /> </TitleWrapper> <HeaderNavigationWrapper> {/* Desktop navigation links */} <Navigation /> {/* Desktop cart button */} <CartButton /> </HeaderNavigationWrapper> </HeaderInner> </PageHeader> ); }; //.. const HeaderNavigationWrapper = styled.div` display: none; @media (min-width: 1000px) { align-items: center; display: flex; } `; 

如果您刷新,您现在应该能够在标题中看到显示购物车按钮。

第 9 步:添加一些样式

最后一步是为我们的站点和组件添加样式。

当我们构建 Frontity 项目时,我们安装了一个预定义的主题,但我想对商店进行更多自定义,并为我们创建的组件添加一些样式。

让我们为“添加到购物车”按钮和我们的产品添加一些样式。

为此,请在位于packages/twentytwenty-theme/src/components/styles/global-styles.js的全局样式文件中添加一个名为snipcartStyled的新常量:

const snipcartStyle = (colors) => css` .snipcart-add-item { padding: 10px; border-radius: 4px; cursor: pointer; transition: .2s ease-out; transition-property: color,border-color,background-color,box-shadow; cursor: pointer; color: white; background-color: #1a4db3; } .snipcart-add-item:hover { box-shadow: var(--shadow-buttonPrimary-hover,0 10px 4px -8px rgba(0,0,0,.5)); background-color: #0d59f2; } .snipcart-checkout { padding: 5px; cursor: pointer; background: none; } .product-price { display: flex; align-items: center; font-size: 1.5em; } .SectionContainer { display: flex; justify-content: center; } `; const productStyle = (colors) => css` img { display: block; margin-left: auto; margin-right: auto; width: 50%; max-width: 100px; padding: 10px; } article { text-align: center; padding: 5px; } `; //.. const globalStyle = (colors) => css([ cssReset, documentSetup(colors), accessibilitySettings, elementBase(colors), elementBase700, elementBase1220, listStyle, quoteStyle(colors), codeStyle(colors), mediaStyle(colors), tableStyles(colors), snipcartStyle(colors), ]); export default globalStyle; 

如您所见,我们还需要将此样式对象添加到我们传递给在globalStyle函数中调用的css函数的数组中。

而已。您现在拥有一个基于 WordPress 和 React 的电子商务网站!

现场演示和 GitHub 存储库

Frontity WordPress 演示主页

在此处查看现场演示

在此处查看 GitHub 存储库

结束的想法

作为非开发人员,我喜欢并欣赏 Frontity 为使用 WordPress 构建静态站点带来的便利。我也喜欢只使用 JavaScript 进行开发(一旦我们的 WordPress 实例被构建和部署)。

Frontity 的零设置也很适合使用。无需配置路由和 API 加快了开发过程。

你试过前沿吗?在评论中让我知道您对这个框架的想法以及您的体验如何。

原文链接:https://devpress.csdn.net/cms/62f9ab297e6682346618dcb9.html

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享