Next.js: 静态生成/SSG 改进

创建于 2019-11-25  ·  250评论  ·  资料来源: vercel/next.js

概括

通过提供基于每页进行静态生成和服务器端渲染的方法,让 Next.js 成为完全混合的。

  • 两种新的每页数据获取方法

    • getStaticProps - 在next build时间选择加入静态生成 (SSG)。

    • getServerSideProps - 选择加入按需呈现的服务器端呈现 (SSR)。

  • 一种从动态源静态生成(SSG)路由集的新方法

    • getStaticPaths - 返回动态路由的参数列表以进行静态生成(SSG)

此 RFC 专门讨论 API 的添加。 所有新功能都完全向后兼容,可以逐步采用。 此 RFC 不引入任何弃用。

背景

在构建网站或 Web 应用程序时,您通常必须在两种策略之间进行选择:静态生成 (SSG) 或服务器端渲染 (SSR)。

Next.js 允许您构建混合应用程序,允许您为每页选择使用哪种策略。 与Next.js 9,没有书页开始getInitialProps获得静态优化和输出.html在文件next build

但是,您可能希望在为特定用例生成静态页面时进行数据提取。

例如,从网站的 CMS 或博客部分静态生成营销页面。

在这种情况下,使用getInitialProps会让你选择加入 SSR。

Next.js 目前有一个next export命令,这使得应用程序完全 SSG,失去了 Next.js 的混合特性。

如果您将next exportgetInitialProps ,则会出现另一个问题。 getInitialProps在构建时调用(这很好),但是当您使用next/link在页面之间移动时getInitialProps被称为客户端,而不是使用next export结果。

这也意味着在客户端转换时直接调用数据源(CMS / API 端点),如果您的数据源关闭,则在页面之间移动时客户端转换会中断。

我们与 HashiCorp 等 Next.js 中的 SSG 和next export重度用户合作(感谢 @jescalan),并广泛研究了引入两种新数据获取方法的正确约束: getStaticPropsgetServerSideProps 。 但也是一种提供参数来为动态路由静态生成静态页面的方法: getStaticPaths (替换为每页的exportPathMap )。

这些新方法与getInitialProps模型相比具有许多优势,因为 SSG 与 SSR 之间存在明显区别。

  • getStaticProps将页面标记为在构建时静态生成(运行时next build
  • getStaticPaths允许返回在构建时为动态路由生成的参数列表
  • getServerSideProps将页面标记为在每个请求上都在服务器端呈现,并且与当前使用服务器时的getInitialProps行为最相似。

分离这些方法还允许我们提供可以使用 TypeScript 键入的正确上下文对象。 当您选择特定的渲染策略时,您会得到正确的值,目前使用getInitialProps您必须猜测使用 TypeScript 时 SSG 与 SSR 上可用的内容。

此外,通过明确这些方法,我们可以更清楚地记录不同的权衡。

执行

请注意,所有这些方法都是页面组件文件中的顶级方法,不能嵌套,类似于getInitialProps

getStaticProps

使用getStaticProps意味着页面将在构建时 (SSG) 静态呈现。

这种新方法将允许您为页面提取数据,该页面将在next build时间静态生成到.html文件中。

Next.js 还会自动生成一个 JSON 文件,其中包含next build时间的getStaticProps的结果。 这用于客户端路由。

当客户端通过next/linknext/router路由时,Next.js 将获取此 JSON 文件以获取在客户端呈现页面所需的道具。

属性在props键下返回,以便将来可以引入其他选项。

// pages/index.js

// getStaticProps is only called server-side
// In theory you could do direct database queries
export async function getStaticProps(context) {
  return {
    // Unlike `getInitialProps` the props are returned under a props key
    // The reasoning behind this is that there's potentially more options
    // that will be introduced in the future.
    // For example to allow you to further control behavior per-page.
    props: {}
  };
}

context将包含:

  • params - 在动态路由上的参数。

getStaticPaths

这是动态路由的getStaticProps用法的扩展。

getStaticPaths取代了对exportPathMap并且可以按页工作。

由于您可能希望静态生成具有动态参数的 url 列表,例如下面的示例slug 。 Next.js 将提供一个getStaticPaths方法,允许返回一个 url 列表。 由于它是一个async方法,您还可以从 CMS 等数据源中获取该列表。

// pages/blog/[slug].js

// `getStaticProps` gets a `params` object holding the dynamic parameters
// For `/blog/hello-world` it would look like `{ slug: 'hello-world }`
export async function getStaticProps({ params }) {
  return {
    props: {}
  };
}

// `getStaticPaths` allows the user to return a list of parameters to
// render to HTML at build time.
export async function getStaticPaths() {
  return {
    paths: [
      // This renders /blog/hello-world to HTML at build time
      { params: { slug: "hello-world" } }
    ]
  };
}

倒退

在许多情况下,您可能不希望在构建时预渲染应用程序中的每条可能路线(例如,如果您有数百万个产品)。 出于这个原因,Next.js 将自动生成一个fallback页面,该页面是页面尚未生成时的页面渲染(以便可以显示加载状态)。

服务的确切行为将是:

  • 传入请求

    • Next.js 检查路径是否在构建时生成

    • 如果路径是生成的



      • 直接上菜



    • 如果路径没有生成



      • 提供后备服务


      • Next.js 在后台渲染页面(带有数据)并将其添加到生成的页面列表中


      • 对同一路径的后续请求将服务于生成的页面


      • 这确保用户始终拥有快速体验,并且永远不会因服务器渲染而出现缓慢的 TTFB,同时保留快速构建和静态生成属性



如果您希望在构建时未生成的路径导致 404,也可以通过从getStaticPaths返回fallback: false getStaticPaths

// `getStaticPaths` allows the user to return a list of parameters to
// render to HTML at build time.
export async function getStaticPaths() {
  return {
    // Opt-out of the described fallback behavior
    fallback: false,
    paths: [
      // This renders /blog/hello-world to HTML at build time
      { params: { slug: "hello-world" } }
    ]
  };
}

getServerSideProps

使用getServerSideProps ,页面不是静态生成的 (SSG),而是根据对服务器的每个请求 (SSR) 按需呈现。

Next.js 还将自动公开一个 API 端点,该端点返回调用getServerSideProps 。 这用于客户端路由。

当客户端通过next/linknext/router路由时,Next.js 将获取此公开的 API 端点以获取 JSON 数据,该数据将转换为在客户端呈现页面所需的道具。

此方法与当前的getInitialProps最相似,主要区别在于getServerSideProps始终在服务器端执行,而不是在浏览器中执行。 在服务器端渲染或客户端路由时的 API 获取。

getStaticProps类似,属性在props键下返回。

// pages/index.js

// getServerSideProps is only called server-side
// In theory you could do direct database queries
export async function getServerSideProps(context) {
  return {
    // Unlike `getInitialProps` the props are returned under a props key
    // The reasoning behind this is that there's potentially more options
    // that will be introduced in the future.
    // For example to allow you to further control behavior per-page.
    props: {}
  };
}

context将包含:

  • params - 动态路由上的参数
  • req - HTTP 请求对象
  • res - HTTP 响应对象
  • query - 查询字符串(不完全确定,但可能需要)

作者: @timneutkens@Timer@ijjk 、@lfades。 与@rauchg@jescalan和其他人合作🚀

最有用的评论

下一代静态站点生成 (SSG) 支持已在 Next.js 9.3 中稳定发布!

此版本还包括对“预览模式”的支持,或者能够绕过静态预渲染页面并为授权用户按需渲染页面。

您可以在我们的博客文章中阅读更多相关信息。 如果您有更多的动手经验,请直接进入我们的文档

所有250条评论

export async function getStaticProps(context) {
  return {
    // Unlike `getInitialProps` the props are returned under a props key
    // The reasoning behind this is that there's potentially more options
    // that will be introduced in the future.
    // For example to allow you to further control behavior per-page.
    props: {}
  };
}

我很想知道在什么情况下我们需要返回除props可以包含的数据之外的其他数据。 我发现在线解释“进一步控制每页的行为”有点含糊。

看起来很有趣! 他会代替getInitialProps还是一起替代? 例如,对于我们的用例,数据获取 API 是一项公共服务。 所以在客户端导航上,我们希望客户端直接调用 API 层,而在 SSR 上,服务器调用它。 展望未来,这个用例会继续由先前的方法解决吗?

我很想知道在什么情况下我们需要返回除props可以包含的内容之外的其他数据。 我发现在线解释“进一步控制每页的行为”有点含糊。

更重要的是对方法进行未来验证,以便我们以后可以在需要时对其进行扩展。

看起来很有趣! 他会代替getInitialProps还是一起替代? 例如,对于我们的用例,数据获取 API 是一项公共服务。 所以在客户端导航上,我们希望客户端直接调用 API 层,而在 SSR 上,服务器调用它。 展望未来,这个用例会继续由先前的方法解决吗?

一般来说,这种行为有一些缺点,例如从世界上的某些地区可能会很慢的瀑布提取。 getServerProps方法允许更有效地缓存响应。

这看起来真的很有趣! 好主意!

我对部署有担忧...

让我们想象一下我在 Now 上主持。
对于第一次部署,很明显整个应用程序都建立在部署之上。

然后,我更改了 CMS 中的一些内容,并希望仅触发 SSG 页面的重建,但应用程序代码没有更改。

立即警报响起,在这种情况下,如果我触发构建,则有两种可能的解决方案:

1)什么都没有重建,因为一切都被缓存了 - 没有代码改变和blabla。
2)我--force它,现在“一切”都得到重建,但我只需要重建 SSG 页面。

_这些只是假设,因为这取决于构建系统本身 - 他们对 Next 的了解程度_

这可能会影响任何其他托管解决方案。

Next 本身有一个.next/cache ......这将如何解决?

@joltmode目前每个静态站点生成器基本上都是这种情况。 .next/cache在 Now 上的部署之间保留并重复使用。 请记住,您目前可能正在将 getInitialProps 用于这种情况下的缓存(可能是 https://zeit.co/blog/serverless-pre-rendering),它在无服务器函数中动态呈现,然后缓存在我们的 CDN 上,这如果您使用getServerProps行为仍然完全正常并且将继续工作。

真的很棒,非常适合我们将 Next 用于客户项目的方式,并且会删除我们复制的一些样板代码。

需要考虑的一件事是 getStaticProps 和 getServerProps 的命名,如果它们将来返回 { props } 和潜在的其他选项,*Props 不会混淆吗? 也许 getStaticConfiguration、getStaticSetup、getStaticOptions 会更通用?

@kibs返回值总是与道具的处理方式有关。 所以命名很好imo。

这简直太棒了! 这解决了我最近在开发私人和专业 Web 应用程序时遇到或可能想到的每个用例和需求。 你只是阻止我启动我自己的混合网站生成器,谢谢!

我还可以认为新方法比之前的getInitialProps()exportPathMap()更好,当我开始使用 Next.js 并深入研究 SSR / SSG 时,这听起来让我有点困惑。 每页方法对我来说也更有意义。

迫不及待想试试这个!

只是一个旁注:在最后一个例子中,我认为getServerProps()缺少一个context参数。

只是一个旁注:在最后一个例子中,我认为 getServerProps() 缺少上下文参数。

固定的!

这听起来很棒! 我只是想从 TypeScript 用户的角度来看,如果将getStaticPropsgetStaticPathsgetServerProps作为页面组件上的静态方法(比如目前的getInitialProps )更容易正确输入/使用。

const Page: NextPage<Props> = (props) => ...

// Explicit types needed here
export const getStaticPaths: NextGetStaticPaths<Params> = () => ...
export const getStaticProps: NextGetStaticProps<Props, Params> = (context) => ...
export const getServerProps: NextGetServerProps<Props> = (context) => ...

export default Page

// vs.

const Page: NextPage<Props, Params> = (props) => ...

// Static method types come from NextPage<Props, Params>
Page.getStaticPaths = () => ...
Page.getStaticProps = (context) => ...
Page.getServerProps = (context) => ..

export default Page

@herrstucki这种方法的问题在于,摇树变得非常困难(阅读:几乎不可能)。 这意味着不必要的代码将被传送到浏览器。

@timneutkens好点……但是单独的文件会不会更有意义? 或者像这样_可靠地_可以摇树吗?

// This should all be removed in client-side code …
import {fetchQuery, queryTag} from 'big-data-fetching-lib';
const query = queryTag`...`
export const getStaticProps = async () => ({ props: await fetchQuery(query) })

// Only this should be included client-side
export default (props) => ...

@herrstucki我们可以可靠地将其摇一摇,但我们仍在讨论是否有一个单独的文件。 不过,我个人更喜欢单文件方法。

看起来很有趣! 他会代替getInitialProps还是一起替代? 例如,对于我们的用例,数据获取 API 是一项公共服务。 所以在客户端导航上,我们希望客户端直接调用 API 层,而在 SSR 上,服务器调用它。 展望未来,这个用例会继续由先前的方法解决吗?

一般来说,这种行为有一些缺点,例如从世界上的某些地区可能会很慢的瀑布提取。 getServerProps方法允许更有效地缓存响应。

当然,但我说的是完全避免到反应服务器的 RTT。 考虑服务器的 SSR 输出缓存在 CDN/缓存服务器代理的情况。 再加上为客户端导航直接调用不同 API 层(网络/应用程序/所有客户端通用)的数据获取,意味着 Next.js 服务器层不必在高流量场景中扩展太多。

我理解您对瀑布式获取的观点,但让消费者能够将 Next 服务器视为 SSR 层而不是数据源将允许更好的扩展设置。

看起来很有趣! 他会代替getInitialProps还是一起替代? 例如,对于我们的用例,数据获取 API 是一项公共服务。 所以在客户端导航上,我们希望客户端直接调用 API 层,而在 SSR 上,服务器调用它。 展望未来,这个用例会继续由先前的方法解决吗?

一般来说,这种行为有一些缺点,例如从世界上的某些地区可能会很慢的瀑布提取。 getServerProps方法允许更有效地缓存响应。

当然,但我说的是完全避免到反应服务器的 RTT。 考虑服务器的 SSR 输出缓存在 CDN/缓存服务器代理的情况。 再加上为客户端导航直接调用不同 API 层(网络/应用程序/所有客户端通用)的数据获取,意味着 Next.js 服务器层不必在高流量场景中扩展太多。

我理解您对瀑布式获取的观点,但让消费者能够将 Next 服务器视为 SSR 层而不是数据源将允许更好的扩展设置。

我认为您误解了这种新行为意味着您实际上可以在 CDN 上缓存完整结果,因为 CDN 支持动态响应。 以前使用 getInitialProps 无法可靠地实现这一点。

@timneutkens我玩弄金丝雀,试图将一些babel-plugin-preval代码移植到getStaticProps 。 我遇到了fs

我正在尝试读取我的./pages/blog/目录的 .md 文件并遍历它们,以便我可以使用我的所有帖子制作一个博客索引页面

import React from 'react';
import Link from 'next/link';
import fs from 'fs-extra';

const Index = ({ posts }) => (
  <div>
    Hello World. <Thing msg="hello" />
    <Link href="/thing">
      <a>About</a>
    </Link>
    {posts.map(p => (
      <div key={p.title}>{p.title}</div>
    ))}
  </div>
);

Index.getStaticProps = async () => {
  const items = await fs.readdir('./pages/blog');
  items.forEach(path => /* .... do some stuff ... */ )
  return { props: { posts: items } };
};

export default Index;

此代码导致此错误:

Module not found: Can't resolve 'fs' in '/Users/jared/Downloads/nextjs-typescript-template/node_modules/fs-extra/lib'

来自 Razzle 的 IIRC,这个错误与 webpack 的文件系统存根(或缺少它)有关。 我想我曾经通过将它添加到 webpack 配置中使用 Razzle 解决了这个问题。

node: {
  fs: "empty";
}

我试过这个 next.config.js,但它只会让错误消失。 尽管fs / fs-extra似乎实际上不起作用,或者它起作用了,而且路径可能不起作用(我不清楚)。 对此有什么想法吗?

我的另一个问题,更笼统地说,是您想象在getStaticProps使用 import 与 require 的最佳实践是什么。 如果我没记错的话,我上面的代码片段将尝试在 React 中以同构方式导入fs-extra ? 因此,将导入更改为这样的内联要求会更好吗?

js Index.getStaticProps = async () => { const fs = require('fs-extra'); // only require when needed at SSG const props = await fs.readdir('./pages/blog'); return { props: { posts } }; };

我认为您误解了这种新行为意味着您实际上可以在 CDN 上缓存完整结果,因为 CDN 支持动态响应。 以前使用 getInitialProps 无法可靠地实现这一点。

啊,我想我明白你的意思了。 这是否意味着第一代 SSR 上的getServerProps会创建一个唯一的端点,在内容可寻址哈希中,也许在 URL 中,然后我们可以在 CDN 上缓存? 唯一的缺点是所述缓存不能在非 Next 应用程序(android / ios)和 Next 应用程序之间共享。 此外,对于外部数据源,缓存控制指令位于上游,但由于 Next 将承担提供数据的责任,因此我们需要 API 或道具来为生成的数据端点指定这些指令。

@jaredpalmer我假设https://github.com/zeit/next.js/issues/9524#issuecomment -558628066(包括我对可靠的 tree-shakeability 的担忧)将通过拥有一个单独的文件来解决,该文件将与客户端捆绑代码? 例如

pages/
    foo.js
    foo.data.js (<- exports getStaticProps etc.)

or:

pages/
    foo.js
pages-data/
    foo.js (<- exports getStaticProps etc.)

@jaredpalmer摇树尚未在 Canary 上实现。

一如既往,感谢你们所做的一切。 Next.js 使用起来绝对是一种乐趣,正如我之前所说,几乎每个功能发布都让我们_减少_我管理的代码库的大小。 太奇妙了。

很难批评这个 RFC,因为正如所写的,它对很多应用程序立即有用。 但是,我确实想解决我不确定是否同意的一句话:

getStaticPaths取代了对exportPathMap并且每页都有效。”

在某些应用程序中,在构建时知道路由是不切实际或不可能的。 一些例子是:

  • 用户个人资料页面
  • 产品页面(适用于库存快速变化的公司)
  • 销售订单详情页面

像这样的页面的路由可能采用/entity-name/entity-id而 Next 的动态路由非常有效,因为您可以执行router.push('/customers/[customerId]', '/customers/baer') 。 还有一个问题。 如果您打算使用 Serve、Netlify、NGINX 等静态地提供这些文件,您需要生成一组重定向,以便用户不会在页面刷新时收到 404,为此,您仍然需要exportPathMap

以下内容几乎按原样从我经常处理的代码库中复制而来:

const buildServeConfig = redirects => {
  const config = {
    public: `dist`,
    trailingSlash: true,
    rewrites: redirects
  };

  const outputPath = `${__dirname}/serve.json`;

  fs.writeFile(outputPath, JSON.stringify(config, null, 2), err => {
    if (err) {
      throw err;
    }
    // eslint-disable-next-line no-console
    console.log(`Generated: ${outputPath}`);
  });
};

...

exportPathMap: function(defaultPathMap, { dev, outDir }) {
  const redirects = Object.entries(defaultPathMap)
    // No need to create a redirect rule for `/dirname/` or `/dirname/index.html`
    .filter(([url]) => url !== `/` && url !== `/index`)
    .map(([url, { page }]) => ({
      // Replaces /[customerId] with /:customerId
      source: url.replace(/]/g, ``).replace(/\[/g, `:`),
      destination: `${page}/index.html`
    }));

  // By default, the routes are sorted such that a route like `/order/:orderId`
  // comes before `/order/new`. Since the `:orderId` portion of `/order/:orderId` 
  // is a wildcard, the route `/order/new` will be a match and consider `new` 
  // as a value for `:orderId`. To get past this, we sort the redirects by the 
  // number of parameters in ascending order.
  const sortedRedirects = [...redirects].sort(
    (currentRedirect, nextRedirect) =>
      currentRedirect.source.split(`:`).length >
      nextRedirect.source.split(`:`).length
  );

  buildServeConfig(sortedRedirects);

  return defaultPathMap;
}

我知道这个 RFC 没有弃用或删除任何 API,我也认识到可以通过遍历构建目录来构建这些重定向,所以即使它被弃用,我也有一个很好的逃生舱口。 但是,它并没有完全“消除对getStaticPaths的需要”。

再次感谢您对如何运行这个项目的体贴

getStaticProps / getStaticPathsgetServerProps互斥的吗? 即是否可以同时预渲染部分和动态部分?

是的,它们是一种静态生成,一种是服务器端渲染。

这解决了我在迁移到 Next 之前从 Gatsby 中错过的一件大事:

我们有一个完整的(100 多字节)JSON 文件,我们从中提取数据以呈现永不更改的页面。 在 Gatsby 中,我们将 JSON 文件加载到 GraphQL 模式中并对其进行查询,只获取渲染给定页面所需的数据。 使用 Next,我们发现最简单/最干净的方法是import monolith from './monolith.json' ,它需要用户下载整个 JSON 文件。

这个 RFC 100% 解决了这个用例,并使 Next 在 Gatsby 闪耀的领域更接近于与 Gatsby 相当(显然,Gatsby 不能执行运行时 SSR,所以我只谈论静态构建时渲染)

@timneutkens ,感谢您的 RFC!

我最近与 @rauchg 讨论了 Next.js 的一个用例。

Next.js 提供非常流畅的 DX 和一些合理的默认值。 因此,我有兴趣将 Next.js 用于仅客户端呈现的应用程序,即智能电视应用程序。

智能电视应用程序几乎是由电视浏览器引擎运行的经典网络应用程序:

  1. 该应用程序打包成一个包:样式、脚本、图像、_index.html_、证书和电视配置文件。
  2. 捆绑包提交给平台的应用商店进行审核。
  3. 然后该捆绑包作为应用程序从商店安装并由用户运行。

问题是捆绑包由电视设备本身静态托管,而不是从服务器加载。 因此,不可能有 SSR 选项(Node.js 不会出于这些目的向开发人员公开)。 但应用程序本身是动态的(比如 Netflix)。

因此,我们需要运行由静态 Web 服务器托管的 SPA。

据我了解,完全退出getServerProps (或getInitialProps )将有助于避免 SSR。 但是在客户端动态渲染会发生什么? 在这种情况下路由呢? 根据这个 RFC,这个问题还没有得到解决。 @timneutkens ,请您建议在 Next.js 中启用仅客户端渲染的最佳方法吗? 以及它是否适合 Next.js? 谢谢!

PS 如果您认为最好单独讨论它,我可以为此用例创建一个问题。

@grushetsky你能不能创建一个不同的问题。 这与 RFC 中讨论的问题完全不同👍

@timneutkens这个 RFC 的承诺是让我对 Next 超级兴奋的事情之一! 只是为了澄清, getInitialProps仍然存在,对吧?

正确的@outdooricon -- getInitialProps将在可预见的未来继续存在。

根据 RFC:

此 RFC 专门讨论 API 的添加。 所有新功能都完全向后兼容,可以逐步采用。 此 RFC 不引入任何弃用。

伟大的 RFC,为此感到非常兴奋!

我一直在考虑与特定用例相关的getServerProps ,将结果放入缓存中。 由于这变成了 API 端点,并且结果作为道具传递给组件,是否有规定的方法将结果放入外部缓存(如 Redux、GraphQL 缓存等)等客户端?

如果我正确理解getInitialProps ,因为它是静态和异步的,Next 有机会在第一次渲染组件之前等待它完成。 这让我们把东西放到一个外部缓存中。 getServerProps不会是这种情况,因为它在服务器上运行,并且在组件生命周期中将内容放入缓存中似乎意味着我们必须在缓存中没有数据的情况下进行渲染,即使它在道具中可用?

这当然可能是故意的,我可能会遗漏一种方法,但我想我会问是否考虑过它?

编辑:我想这也适用于getStaticProps 。 😄

也许我在某处错过了它,但是当内容被缓存但它在数据库中更新或创建了新的博客文章时,我们如何处理这种情况? 是否需要自动进行新构建? 大概吧。

首先! 很棒的提议,对于大多数人的用例来说,这是对exportPathMaps的巨大改进。 真的很感激。 话虽如此,我正在努力理解我们将如何使其与路线国际化一起工作。

关于如何处理 i18n 前缀路由有什么建议吗? 我的特定用例需要在具有不同国家/地区语言前缀和 url 的页面上构建数千个。

/nl/brillen
/gb/glasses
/es/gafas
...

当 url 的前缀众所周知时, getStaticPaths似乎真的很有帮助,如您的示例(使用/blog/[id].js )。 但是您认为getStaticPaths实现是否需要在根级别生成路径,同时具有动态前缀(国家/地区语言)和动态路径?

@reaktivo pages/[lang]/blog/[id].js -> 在getStaticPaths提供所有静态渲染的 url。

@timneutkens知道什么时候可以使用/可测试吗?

一般来说,我们不会发布 ETA,因为我们针对生产应用广泛测试功能以确保解决方案是正确的。

这种改进将使我完全弃用我的“未维护”的表型项目(react ssg,除了我之外没有人使用)。 很高兴看到 Next.js 添加了这个缺失的部分!

我想澄清一个疑问。 考虑使用像 wordpress 这样的 CMS。 据我了解,使用 getStaticPaths 方法,我将获取所有帖子并传递如下列表:

export async function getStaticPaths () {
  return [
    // This renders / blog / hello-world to HTML at build time
    {params: {slug: "hello-world"}}
  ];
}

每个帖子的 slug 将用于 getStaticProps 方法来获取内容。
这将发生在 npm build 中。
我的问题是关于构建后将添加的新帖子。
是否会使用 getStaticProps 方法来通过 slug 获取这个新帖子?
这篇新文章是否有一个 .html 文件,就像之前版本中的文件一样?
我喜欢和 next 一起工作,在我有的几个项目中,这会非常好。

没有直接关系,但支持人员无法给我一个与我的问题相匹配的答案。

您在这里建议的可能是解决方案,但与此同时,我无法让 nextJS 构建基于 webhooks 更改的 JAMSTACK。

如果我有 getInitialProps 我将被服务器渲染。
如果我不这样做,我只是 CDN 化,但没有预渲染不是吗? 只要 XHR 没有返回,页面就会没有内容(再见 SEO)

你现在有任何运行带有 nextJS 的 Jamstack 的例子吗,我们可以在 netlify 上做。

谢谢,
安德烈亚斯

@ScreamZ - 我认为,这种变化是使用 nextjs 构建完全静态站点的原因。 很长一段时间以来,我们已经能够使用next export将 nextjs 站点编译为静态站点,但它仍然会使用getInitialProps获取有关客户端路由转换的数据。 通过使用getStaticProps ,您可以运行客户端转换而无需获取任何其他数据—— getStaticProps所有获取数据在构建时获取一次,并且不会在您的除非您再次重建,否则现场直播。 这是数据驱动静态站点的经典架构,通过 webhook 将您的数据源链接到您的主机,当数据源发生变化时,您告诉主机重建您的站点。

有很多完全静态的 nextjs 网站的现有示例,在 netlify 上运行 nextjs 网站是微不足道的。 我公司的网站目前在nextjs上运行,由netlify托管,希望这是一个很好的例子。

非常值得注意的是,zeit 的托管服务也是值得强烈考虑的。 定价非常相似,并且它们与 nextjs 站点的集成是首屈一指的 - 您实际上根本不需要配置任何东西,您只需链接 github 和 zeit 的托管将识别您正在运行 nextjs 并自动配置和部署一切。

这绝不是广告,我不为时代工作,只是真正的代言。 你绝对可以让它与 netlify 一起工作,我个人有几个站点作为证明。 但是您需要彻底了解 nextjs 的工作原理,并且需要确保所有内容都正确配置以使其在 netlify 上顺利运行。 如果您正在为 nextjs 站点寻找最简单、最简单的托管服务,我会尝试使用 zeit 托管服务。

@jescalan感谢您的精彩分享🙏🏻

我在 netlify 中使用 NextJS 没有问题,因为您可以使用Publish directory来指定out文件夹。 但是在 zeit 现在,没有办法说,请不要使用 SSR,而是使用next export完全静态化。

@ScreamZ确实如此,但这取决于您如何准确定义“完全静态”站点。 如果您使用 zeit 的托管服务为所有页面使用getStaticProps ,您将获得的实际上等同于静态站点,即使它不运行next export ,因为所有页面都带有getStaticProps仅在站点部署时构建,之后直接从 CDN 提供服务。

主要区别在于,据我所知,没有办法强制所有页面在 zeit 的托管上保持静态(编辑:zeit 最近更改了它,以便任何配置包含exportPathMap站点都将运行一个完全静态的站点,所以这不再是真的)。 带有getStaticProps页面的行为与由next export生成的页面完全相同——页面的单个静态副本在每次点击时直接从 CDN 提供。 但是您也可以使用getServerPropsgetInitialProps运行一些页面,它们将表现为服务器呈现的页面。 我个人认为这是一个好处——如果需要 SSR 路由,您可以简单地使用不同的数据获取方法,并且该单个路由现在是 SSR,而所有其他路由可以保持静态。

@jescalan谢谢,

所以只需要等待实现这个,同时将使用 netlify 进行静态

有没有关于 SSG 配置的故事? 具体来说,我们希望使用共享构建工件,但使用不同的 QA/prod 配置运行next export 。 这些配置值只能在getStaticProps读取。 这会直接使用serverRuntimeConfigpublicRuntimeConfigprocess.env吗?

@ScreamZ @jescalan我今天与@Timer一起在 Now 上获得了零配置next export支持(他应得的所有功劳)。 你可以做:

"build": "next build && next export"

它会自动工作。

让我知道进展如何🙏

是的,我是那个询问支持的人,他们告诉我这已经实现了😅据我所知,你需要在配置中定义一个导出映射?

@ScreamZ不,您只需添加next build && next export如上所示,它会起作用。

@timneutkens如果我用getServerProps替换getInitialProps ,我是否还需要将target: 'serverless'到配置文件中以启用Server Pre Rendering ? 谢谢。

我们如何尝试这些?

我们如何尝试这些?

我想所有这些方法目前都需要unstable_前缀才能被识别。

例如unstable_getStaticProps

@timneutkens

@ScreamZ @jescalan我今天与@Timer一起在 Now 上获得了零配置next export支持(他应得的所有功劳)。 你可以做:

"build": "next build && next export"

它会自动工作。

让我知道进展如何🙏

我的构建脚本做了更多的事情,但它看起来像一个魅力:

"build": "graphql codegen && next build && npm run export",

此外,它很棒! 这正是我要找的 😅(再见 GatsbyJS,我最喜欢的框架现在和你一样强大!)

非常感谢您的这种反应。

我也升级到9.1.6并且我惊讶地看到
Screenshot 2019-12-21 at 19 25 43

我以为那个线程是一个 RFC,它看起来已经向我们开放了啊哈,不是吗?
但是,Typescript 类型在 9.1.6 中未启用。

该死的,我现在为此大肆宣传! 🤣

最后问题:

  • 如果我得到它, getInitialProps将来会被弃用吗? 或者在某些情况下它仍然相关? 一个例子?
  • next export也可以弃用,只支持带有getStaticPropsnext build

谢谢你的好工具🙏🏻

如果我得到它,将来会弃用 getInitialProps 吗? 或者在某些情况下它仍然相关? 一个例子?

正如最初的 RFC 中所说:

此 RFC 专门讨论 API 的添加。 所有新功能都完全向后兼容,可以逐步采用。 此 RFC 不引入任何弃用。

我以为那个线程是一个 RFC,它看起来已经向我们开放了啊哈,不是吗?

不是,我们正在 ZEIT 应用程序上尝试它,并且一些可见性表面已经登陆(例如你看到的页面树)。

下一次导出也可以弃用,而只支持带有 getStaticProps 和下一次构建的页面?

正确,通常你最终不会使用next export 。 出于向后兼容的原因,它将保留下来,但通常您会希望创建一个混合应用程序,因为它为您提供导出的所有好处,并支持其他功能,例如 API 路由和选择某些页面的服务器端渲染。

我们如何尝试这些?

我想所有这些方法目前都需要unstable_前缀才能被识别。

例如unstable_getStaticProps

强烈建议不要使用它,它是实验性的,可能会在发布之间中断。

所以我一直在玩这个功能,我观察到包含页面数据的 JSON 文件总是在从另一个页面访问 SSG 页面后获取。

你们计划对 JSON 文件进行任何预加载优化吗?
也许在用户即将导航到页面时预加载它(即:用户悬停在 SSG 链接上)或预加载就像您预加载从链接组件引用的其他 js 页面一样。

顺便说一下,喜欢这个功能!

你们计划对 JSON 文件进行任何预加载优化吗?

是的。

就其价值而言,我完全赞成这些 funcs 的可摇树导出,而不是单独的文件。

此功能的状态如何? 它的阻滞剂是什么?

@mikestopcontinues此 RFC 目前正在由我们的团队和一些选定的合作伙伴进行大量内部测试。 如上所述,您可以使用高度实验性的行为! 😄

不过,请不要将生产工作负载迁移到新方法,因为我们仍然可能会以破坏性的方式更新 API。

就我个人而言,我使用它来生成 8 到 20K 页面的静态站点(可能在某些页面上有一些动态请求)。 它工作得很好(除了 Now 的 10K 文件限制),唯一让我感到遗憾的是没有 getStaticPaths 方法,每次重新加载时都会调用 getStaticProps。 一个可能好的行为是第一个调用创建 json 文件,下一个调用使用它。

是否计划了增量构建? 所以只有新的/更改的内容是重建?

如上所述,您可以使用高度实验性的行为

我想测试unstable_getServerProps方法,但目前看起来它被忽略了,而且我无法在zeit/next.js库中的任何地方找到它。 它还没有实施,还是我做错了?

是否计划了增量构建? 所以只有新的/更改的内容是重建?

该实现在设计时考虑了增量重建,但尚不受支持(本 RFC 中也未涵盖)。

请放心,架构已准备就绪,我们将在这些功能稳定后进行探索。
这就是为什么getStaticProps是按页面定义的,而不是为整个应用程序定义一次!

我想测试 unstable_getServerProps 方法,但目前看起来它被忽略了 [...]

getServerProps尚不提供预览版,抱歉!

getServerProps尚不提供预览版,抱歉!

谢谢你的提醒。 我肯定会关注这个线程,因为当它出现时,我有一堆代码可以通过重命名单个函数来替换! 😍

请澄清,我不能 100% 确定getServerProps / getStaticProps当前是否可以使用。

基于此线程:否

但如果是这样的话,那么我想知道为什么我的终端在我运行next build时会提到它,如果它们还不可用? 看到这条消息让我初步假设这些方法正在生产中,我花了一段时间才发现它们没有。 只是对推理感到好奇,或者是否有什么我误解的地方。

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

(下一个版本 9.1.6)

谢谢

@stevenjchang他们可以在pages/**/*.js使用以下语法

export function unstable_getStaticPaths() {} // return [{params: {...}}, ...]
export function unstable_getStaticProps({params: {...}) {} // return {props: {...}}

而且我还应该补充一点,它们很棒,尽管在使用开发服务器时它们的边缘仍然有些粗糙。

尽管在使用开发服务器时它们的边缘仍然有些粗糙。
@mikestopcontinues

你能详细说明一下吗? 没有其他人给我们关于开发服务器体验的负面反馈,我们很乐意解决它!

@Timer我真的很喜欢新的 api。 我在开发期间的主要问题是在每次加载时都会重新请求 json。 这会减慢测试速度,但也会歪曲用户在实际浏览网站时的体验。

“每次加载”是指页面加载吗? 还是重建? 或者...?

@mmmeff每次导航到同一路径时,它都会重新请求 json。 所以如果你在两个页面之间来回点击,你会花费大量时间等待数据。

@mikestopcontinues这是预期的行为,因为在开发中通常最好使用最新的数据。 愿意在新一期中讨论一些更好的启发式方法!

@timneutkens这个 RFC 看起来很有前途。 我有一些关于安全性的问题/疑虑,以及它是如何工作的。

让我们来看一个同时依赖 SSR 和 SSG 的通用业务案例。

语境

我们想在网站(又名“应用程序”)上显示一些信息。
这些信息存储在可通过 GraphQL API 访问的 BDD 中。
其中一些信息是公开的,一些是私人的(即:用户电子邮件/密码)。

该应用程序使用两个阶段:

  • “登台”阶段,客户可以在登台应用程序中看到实时变化(他们通过一些后台或类似的方式更新这些信息)
  • “生产”阶段,客户无法访问,也无法自行更新任何内容。 要更新生产应用程序,必须进行新部署。 (他们要求从他们所说的后台进行新的生产部署)

在这个场景中,我们同时使用 SSR 和 SSG:

  • Staging 应用程序使用 SSR,因为它从 GraphQL API 实时获取数据(在构建页面时)
  • 生产应用程序使用 SSG,因为在进行新部署时,它从 GraphQL API 获取数据并从中生成静态页面(因此它们是静态的,不会再更改,不会对 GraphQL API 进行查询在运行时(至少不是在加载页面时))

这个场景应该足够通用,并且应该是(恕我直言)SSG 使用的主要用例之一。
生产应用程序只不过是登台应用程序的快照。

几个问题:

  1. 这个 RFC 有可能吗? 根据给定的“阶段”(生产/阶段),让相同的应用程序表现不同
  2. 从 GraphQL API 获取的数据是如何注入的?

    • 在登台时,它们是通过 SSR 或 CSR 在用户浏览页面时动态获取的(如果在 CSR 期间获取,将在浏览器上可用)

    • 在生产中,它们是在构建时获取的,但是,它们是否存储在 JS 全局变量中,因此任何人都可以读取? (安全问题,因为我们必须注意不要获取可能在浏览器上可用的敏感数据,类似于使用 CSR 时的做法)

  3. 您对这种混合 SSR/SSG 的方法有任何担忧吗? (安全性、性能、可维护性等)

你打算什么时候发布这个? 它将是重大更新 (v10) 还是向后兼容的更新?

嘿,

你有没有人用自定义服务器尝试过这个解决方案并让它工作?

例子:

// server.js

const express = require('express');
const next = require('next');

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();

  server.get('/blog/:id', (req, res) => {
    console.log('My params needed be passed to page:', req.params);
    return app.render(req, res, '/blogDetail', { id: req.params.id });
  });

  server.listen(port, err => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}`);
  });
});

// blogDetail.js
export async function unstable_getStaticProps(props) {
  console.log('What is passed', props);

  return {};
}

const BlogPostPage = ({ post }) => {
  return <div>Hey</div>;
}

export default BlogPostPage;
# Terminal output

My params needed be passed to page: { id: 'test' }
What is passed { params: undefined }

为什么getStaticProps包含查询字符串? 我目前有一个页面,我必须使用 SSR 来获取查询参数而无需重新渲染。 使用useRouter钩子会导致多次重新渲染,因为查询最初是一个空对象。 这是一个用于转换跟踪的页面,很明显,这是一个非启动页面。

@pjaws RFC 特别提到getStaticProps用于静态生成。 静态 HTML 无法接收查询字符串。

那为什么它可以接收动态URL参数呢? 那有什么不同?

2020 年 1 月 14 日,星期二,上午 1:30,Tim Neutkens通知@github.com
写道:

@pjaws https://github.com/pjaws它特别提到的 RFC
getStaticProps 用于静态生成。 静态 HTML 无法接收
请求参数。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=AMVRRIQCKDJNF4MPWSLYNV3Q5WA2NA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTODN53GWW4300000000000000004
或退订
https://github.com/notifications/unsubscribe-auth/AMVRRIRJXLYC4MC4U7DH7NDQ5WA2NANCNFSM4JRPBELQ
.

因为在getStaticPaths您必须返回将在构建时呈现的页面。

这些变化看起来很有希望,一如既往的伟大工作! 👍

我想知道在_app.js使用getInitialProps _app.js来满足跨页面共享的数据需求(例如设置上下文提供程序)的用例。 我是否正确理解以相同的方式使用getStaticProps是不可能的? 只能在单个页面中定义它吗?

我想知道在 _app.js 中使用 getInitialProps 来满足跨页面共享的数据需求(例如设置上下文提供程序)的用例。 我是否正确理解以相同的方式使用 getStaticProps 是不可能的? 只能在单个页面中定义它吗?

正确,最初它只会用于单个页面。 以后可能会重新考虑。 _app 的 getInitialProps 在导出为静态 HTML 时仍会被调用,因此您可以逐步移动到 getStaticProps。

大家好,一个相关的问题 - 如何处理资产? 因为我现在看到,如果我使用无头 CMS(甚至是 wordpress 或 graphcms 或其他),则资产 url 将用于静态 html。

这里有两个偏好 - 资产链接被这样使用。
但更有可能 - 下载资产,构建 html(本地链接),然后在前面分层 CDN。 这是更容易接受的做法。

这也与使用 Netlify 之类的部署系统密切相关——Netlify 拥有比 DatoCMS 或 Graphcms 之类的东西更适合全球可用的基础设施。 因此,如果我使用 Netlify 作为部署,我希望所有内容都来自 Netlify 域并让它发挥其魔力。

@sandys如果我在https://github.com/zeit/next.js/issues/9054#issuecomment -570427085 中理解正确,您应该下载资产,将它们存储在.next/static并建立链接你自己在getStaticProps

还有使用静态 api 路由的想法,但我不确定您将如何使用它来控制浏览器缓存行为。

@Janpot感谢您链接它。 那里的评论似乎表明这些东西必须自己动手。

请将我的请求添加到内置。 也许#9054 更通用,但我是从 SSG 的角度思考的,这非常重要。

我忘了提及,但资产散列对于 SSG 也是必不可少的。

@homoky ,一直无法让它工作,在此期间你有没有取得任何进展?

@homoky ,一直无法让它工作,在此期间你有没有取得任何进展?

这是不可能的,也没有计划:#10071

😢

@sandys实际上,当您使用https://github.com/zeit/next.js/issues/9081将重写从例如/images到 CMS 时,解决方案要简单得多。 例如在 ZEIT 现在,当添加正确的标头时,它已经缓存了结果,无需额外下载(构建时的大量开销)。

@timneutkens感谢您的回复。
不完全确定你的意思。 所以我们使用 netlify - 您是否建议我们保留 CMS url 并在其前面添加一层 CDN?
我不太确定 netlify(我们计划使用的 cloudfront)是否可以与所有这些服务无缝协作。

如果图像被下载并成为部署的一部分,那么整个问题就会得到极大的简化。 因为我将 CDN 设置为从基本 url 缓存(在我的情况下将从 s3 获得服务)。

不完全确定您的解决方案是否基于我使用 Zeit NOW

如果图像被下载并成为部署的一部分,那么整个问题就会得到极大的简化。 因为我将 CDN 设置为从基本 url 缓存(在我的情况下将从 s3 获得服务)。

这实际上使构建过程变得更加复杂和 10 倍慢,绝对不是更简单。

不完全确定您的解决方案是否基于我使用 Zeit NOW

适用于世界上的每个代理。 包括云前线。

@timneutkens我们实际上不

我当然不提倡你为每个人打开这个。 许多人会很高兴深层链接到 CMS。 但是我们运营着一个高流量的网站,这绝对是我们这样的网站所需要的。

另外,请原谅我,但我不明白您的解决方案。 我们应该如何配置它? 我无法控制 CMS 使用的网址。 有关示例,Datocms开始从服务www.datocms-assets.com/ 。 我们如何使用#9081 中的解决方案?

我们实际上不知道构建过程的时间。 如果需要更长的时间也没关系

这可能适用于您的应用程序,但大多数应用程序并非如此。

但出于多种原因(包括从已知的基本 url 提供的所有资产),最好在构建中进行烘焙。

它真的不必像所说的那样,您可以使用将/images/*代理到 cms url 的重写,例如www.datocms-asset.com/*或类似的。 然后只需使用/images链接所有图像。

请注意,这开始偏离主题。

@sandys实际上,当您使用#9081 将例如 /images 的重写添加到 CMS 时,解决方案要简单得多。 例如在 ZEIT 现在,当添加正确的标头时,它已经缓存了结果,无需额外下载(构建时的大量开销)。

@timneutkens只是为了让我清楚。 在理想情况下,您可以散列图像并将其永久缓存在浏览器中唯一 url 下,内容创建者可以随时更新文件,在 CMS 中使用相同的名称。 所以这意味着在设置中,您建议 CMS 必须负责:

  1. 优化图像
  2. 散列图像并在此散列下提供它们
  3. 提供从图像 url 到散列图像 url 的映射,可以在getStaticProps下载,以将图像 url 重新映射到 CMS 上的不可变对应物

我想,这并非不可能。 只是想确保这是建议的设置。

@Janpot CMS 提供商已经通过为图像等提供唯一的 url 来处理这个问题。

@sandys这与 SSG RFC 无关,因此在发布时可以随意创建一个新问题。

但是,只想提一下,在我们所有人看来,这与 SSG 密切相关。 因为理想的情况是 SSG 导出命令执行此操作。 这在其他情况下通常是不需要的。
最好的情况是在下次导出时将其作为可选功能。

但是,如您所愿 - 尊重您的决定。

但这是next export目前甚至不做的事情。 因此,为什么它是一个全新的东西并且与这个 RFC 无关。

它也不会使用getServerProps和按需渲染。

@Janpot CMS 提供商已经通过为图像等提供唯一的 url 来处理这个问题。

👍是的,有道理。 但这也意味着,如果您在项目中使用图像并希望对其进行优化和缓存,您有两种选择:

  1. 构建自定义 webpack 设置
  2. 使用外部 CMS

编辑:

如果我理解正确, file-loader已经包含CSS。 是否也为 JS 启用它?

@Janpot Sandeep 提到的具体点是网址将来自外部来源,而不是项目本身。 默认情况下包含 file-loader 是一个不同的功能请求。

我注意到,对于部署到 ZEIT Now 的站点,当我有一个使用新静态 API 的动态 URL 页面时,对于尚未使用unstable_getStaticPaths静态生成的页面,函数unstable_getStaticProps在运行时在服务器上运行,而不是返回 404。

例如,我有一个页面/blog/[slug].js ,其getStaticPaths返回数组:

[{ params: { slug: 'hello' } }]

我的getStaticProps有一些逻辑来读取基于 slug 的文件。 当我访问/blog/hello ,页面会按预期预渲染,但是当我访问像/blog/doesnt-exist这样的无效页面时, getStaticProps在运行时运行,我收到错误 500,而不是a 404。或者如果我添加错误处理,则页面呈现,而不是 404,尽管没有在getStaticPaths的输出中列出。

这个逻辑是故意的吗?

这是一个很大的改进。 我们正要编写一些预构建脚本来做到这一点。
我刚刚测试unstable_getStaticProps在 Next 9.2 上将我们的一个站点移动到unstable_getStaticPathsunstable_getStaticProps ,并且运行良好。

exportPathMap相比,我们有一个回归:使用exportPathMap构建路径时,您可以指定如下内容:

{
 "/path/to/page": {page: "/index", query: { pageId: 123 } }
}

并且静态构建将构建

/path
   /to
     /page
       index.html

当您从模板[slug].jsx unstable_getStaticPaths返回等效项时,

[{ slug: '/path/to/page' }]

接下来 9.2 生成“%2Fpath%2Fto%2Fpage”而不是嵌套目录。

/%2Fpath%2Fto%2F
   index.html

构建目录(匹配现有的 exportPathMap 行为)对于我们构建页面的方式很重要。 我们使用单个模板文件,但发布的路径可以任意嵌套。

@dpfavand在这种情况下,您将需要使用全能路线: https : //nextjs.org/blog/next-9-2#catch -all-dynamic-routes

当您尝试返回包含斜杠的路径时,我们可能会发出警告,但在使用[slug].js时行为是正确的,在您的情况下,您需要[...slug].js

预计什么时候落地? 它会在 9.2 的补丁中还是它自己的次要版本?

我们非常感谢围绕此功能的所有兴奋。 正如其他地方提到的,我们通常不会分享功能的时间表,因为我们希望确保它们具有正确的开发人员体验、限制和未来证明。

因为它是一个新功能,所以它是次要的。

是的,我通常会理解,但 9.1.7 博客给人的印象是
它已经在野外了。

2020 年 1 月 17 日星期五下午 5:05 Tim Neutkens通知@github.com
写道:

我们非常感谢围绕此功能的所有兴奋。 如前所述
在其他地方,我们通常不会像我们想要的那样共享功能的时间表
确保他们拥有正确的开发人员经验、限制和未来
证明性。


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=ADKINGF724256WCEFHBFIH3Q6ITRXA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXZDNJK563LNMVXZDNJK563LNMVXDNWJK563LNMVXZDNJK563LNMVXDNJK568JKET300000000000000000000001001000100010001003
或退订
https://github.com/notifications/unsubscribe-auth/ADKINGBVCG6MFMOG5U2FGMDQ6ITRXANCNFSM4JRPBELQ
.

>

拉西特·格雷格
[email protected] [email protected]
手机 (832) 495-9903

有没有像getStaticProps这样的东西,但它只对整个应用程序运行一次而不是每页运行一次?

我的用例是我有一个被多个页面使用的 React Context ( PricingPlansContext ),我希望在构建时从我的外部服务器检索数据(定价计划)一次( next export )。 永远不要在运行时,也不必从每个页面添加到getStaticProps

编辑:在上面找到相关评论: https :

我为此使用了babel plugin-preval`,尽管我也看到人们写了一个
使用 next.config.js 在 exportPathMa() 中创建 json 文件,然后导入
在他们的代码中。

我现在最终使用 npm 脚本编写了一个 json 文件,但感谢您建议 exportPathMap,也许这是一个更好的地方。

@dpfavand在这种情况下,您将需要使用全能路线: https : //nextjs.org/blog/next-9-2#catch -all-dynamic-routes

当您尝试返回包含斜杠的路径时,我们可能会发出警告,但在使用[slug].js时行为是正确的,在您的情况下,您需要[...slug].js

@timneutkens感谢您的跟进。 我试过两种方法都没有成功。 基本上,当在getStaticPaths中将 slug 值指定为字符串时,它根本不会传递给getStaticProps 。 将 slug 值作为数组返回时,构建失败,因为该值必须是字符串。

案例 1,假设一个文件pages/[...slug].jsx ,作为字符串插入:

export async function unstable_getStaticPaths() {
    return [{ params: { slug: 'en/about' } }];
}

export async function unstable_getStaticProps({ params }) {
    console.log('params', params);
    return { slug: params.slug };
}

在上述情况下, params中的getStaticProps是一个空对象 - 没有slug键。

情况 2, pages/[...slug].jsx , slug 作为数组,

export async function unstable_getStaticPaths() {
    const allPaths = Object.keys(pathMap).map(slug => ({ params: { slug } }));
    return [{ params: { slug: ['en', 'about'] } }];
}
export async function unstable_getStaticProps({ params }) {
    console.log('params', params);
    return { slug: params.slug };
}

在情况 2 中,构建失败

> Build error occurred
{ Error: A required parameter (slug) was not provided as a string.
    at _validParamKeys.forEach.validParamKey (/project/node_modules/next/dist/build/utils.js:21:569)
    at Array.forEach (<anonymous>)
    at toPrerender.forEach.entry (/project/node_modules/next/dist/build/utils.js:21:495)
    at Array.forEach (<anonymous>)
    at Object.isPageStatic (/project/node_modules/next/dist/build/utils.js:17:122)
    at process._tickCallback (internal/process/next_tick.js:68:7) type: 'Error' }

我只在上面的getStaticPaths示例中看到路径参数。 是否可以包含查询参数的 SSG 路径? 例如:

/store/widgets/circles-n-squares?sort=price&minWeight=2&color=black

我特别是从电子商务网站的角度考虑,很难在 URL 的pathname中涵盖产品搜索的每一个方面。

我最近在这里发布了一条消息但没有收到回复 - 基本上,当将站点部署到 ZEIT Now 时, getStaticProps的行为就像getServerProps (即忽略getStaticPaths并处理请求动态)-我认为这是一个错误?

@dpfavand我也遇到了同样的事情! 尝试使用基于 CMS 中的页面的动态页面路由为 agilitycms 和 nextjs构建

@timneutkens感谢您的跟进。 我试过两种方法都没有成功。 基本上,当在getStaticPaths中将 slug 值指定为字符串时,它根本不会传递给getStaticProps

案例 1,假设一个文件pages/[...slug].jsx ,作为字符串插入:

export async function unstable_getStaticPaths() {
  return [{ params: { slug: 'en/about' } }];
}

export async function unstable_getStaticProps({ params }) {
  console.log('params', params);
  return { slug: params.slug };
}

在上述情况下, params中的getStaticProps是一个空对象 - 没有slug键。

BTW,小世界! 再次感谢您在 fastr_conf 上发言。

@timneutkens

我对让 next.js 表现得像一个静态站点生成器的想法感到非常兴奋。

我想问一下getStaticPropsgetStaticPaths方法在一次请求大块数据然后用于生成不同页面的情况下如何使用。

例如,我正在使用基于 API 的 CMS 的 JavaScript SDK 客户端,该客户端具有获取所有可用对象的方法。 其中一些对象代表站点页面。

const entries = await cmsSdkCient.getEntries();

到目前为止,我一直在使用exportPathMap方法一次从 CMS 中获取所有条目,并在这些页面的路径与其数据之间生成映射。 exportPathMap函数做了两件事:

  1. 提供地图与他们的数据页和ssr: true由消费getInitialProps以出口时间
  2. 将相同的数据写入ssr: falseinit-props.json文件,并放置在与每个页面的路径匹配的文件夹中。 然后,当从客户端调用getInitialProps ,从匹配页面的init-props.json加载所需的数据。


next.config.js 使用exportPathMap

module.exports = {
  exportTrailingSlash: true,
  exportPathMap: (defaultPathMap, { outDir }) => {
    // load data from CMS
    const objects = await cmsSdkCient.getEntries();

    // create map between page paths and page data
    return objects.reduce((accum, object) => {

      // if the object does not have a slug, it is not a page
      if (!object.slug) return accum;

      const pagePath = '/' + object.slug;
      const ssrQueryData = Object.assign({ ssr: true }, object);
      const clientQueryData = Object.assign({ ssr: false }, object);

      // generate the map for export phase with {ssr: true}
      accum[pagePath] = {
        // using additional fields from the page object,
        // the pageFromPagePath() computes which page file should
        // be used to render the page object
        page: pageFromPagePath(object),
        query: ssrQueryData
      };

      // write json files that will be loaded by client
      if (outDir) {
        const jsonFilePath = path.join(outDir, _.trim(pagePath, '/'), 'init-props.json');
        fse.outputFileSync(jsonFilePath, JSON.stringify(clientQueryData));
      }

      return accum;
    }, {});
  }
}


pages/my_page.js 使用getInitialProps

Index.getInitialProps = async (context) => {
  const ssr = _.get(context, 'query.ssr', false);
  if (ssr) {
    // we are on server, return the data
    return _.get(context, 'query', {});
  } else {
    // we are on client side, request the data through /init-props.json endpoint
    const url = context.asPath + '/init-props.json';
    return fetch(url).then(response => {
      return response.json();
    });
  }
};

我可以看到使用getStaticPropsgetStaticPaths方法的巨大优势,这将减少与保存 JSON 文件和从客户端加载它们相关的大部分代码。

// pages/my_page.js
export async function getStaticProps(context) {
  const objects = await cmsSdkCient.getEntries();
  const props = _.find(object, { type: 'my_page' })
  return { props };
}

// pages/blog/[slug].js
export async function getStaticProps(context) {
  const objects = await cmsSdkCient.getEntries();
  const props = _.find(object, { type: 'post', slug: context.params.slug })
  return { props };
}

export async function getStaticPaths() {
  const objects = await cmsSdkCient.getEntries();
  return objects
    .filter(object => object.type === 'post')
    .map(object => ({ params: { slug: object.slug } }))
}

困扰我的是如何优化工作流程以将所有条目带入一次,而不是每次调用getStaticPropsgetStaticPaths时获取它们?

另一个问题,可能不一定与这个问题有关,但因为我们处于 SSG 和远程数据源的世界,所以值得一问。 假设 next.js 运行在开发模式下,如何通知 next.js 重新执行这些方法以重新获取远程数据并重建站点。

@smnh因为它“只是 JavaScript”,所以您可以获取一次条目并将结果缓存在您的数据获取方法中。 当它在其他页面的 getStatic* 方法中再次被调用时,网络将不会再次受到攻击。

至于你的第二个问题,它会自动这样做。 运行next dev就可以了。

我只在上面的getStaticPaths示例中看到路径参数。 是否可以包含查询参数的 SSG 路径? 例如:

/store/widgets/circles-n-squares?sort=price&minWeight=2&color=black

我特别是从电子商务网站的角度考虑,很难在 URL 的pathname中涵盖产品搜索的每一个方面。

我认为这在 ssg 的背景下没有意义。 SSG 为每个条目输出一个文件 - 查询参数不是文件名的一部分,因此您需要一个服务器层将请求重写为实际文件。 (在上面的示例中,您的静态文件名是什么?)我建议考虑预渲染默认视图(如果您访问没有分面的页面,您会得到什么)并在客户端更新(如果请求中有查询参数)。 但这成为超出此 SSG RFC 的问题。

@dpfavand我也遇到了同样的事情! 尝试使用基于 CMS 中的页面的动态页面路由为 agilitycms 和 nextjs构建

@timneutkens感谢您的跟进。 我试过两种方法都没有成功。 基本上,当在getStaticPaths中将 slug 值指定为字符串时,它根本不会传递给getStaticProps
案例 1,假设一个文件pages/[...slug].jsx ,作为字符串插入:

export async function unstable_getStaticPaths() {
    return [{ params: { slug: 'en/about' } }];
}

export async function unstable_getStaticProps({ params }) {
    console.log('params', params);
    return { slug: params.slug };
}

在上述情况下, params中的getStaticProps是一个空对象 - 没有slug键。

BTW,小世界! 再次感谢您在 fastr_conf 上发言。

嘿! Nextjs 团队开始解决这个问题,有一张票可以解决当前金丝雀实现的一些其他问题: https :

@smnh我最终做的是有一个脚本,可以在运行构建 + 导出之前预取共享内容并将其保存为 JSON。 然后,您只需将该 JSON 作为模块直接导入页面中即可。

对于重建,我在 CMS 中设置了 webhooks,以在相关内容更改时触发 Netlify 构建挂钩。 GetStaticProps 然后可以只获取页面特定的内容。

谢谢@zeusdeux
关于:

至于你的第二个问题,它会自动这样做。 运行下一个开发,你就可以开始了。

如果我将它们缓存在一个模块中,然后更改 CMS 中的数据,缓存将如何失效并由dev重新运行,但不会停止 next.js 并再次运行它:)

如果我将它们缓存在一个模块中,然后更改 CMS 中的数据,缓存将如何失效并由dev重新运行,但不会停止 next.js 并再次运行它:)

getStaticPaths仅在生产构建中被调用,因此当从该函数调用时,您只能告诉获取方法在模块状态中缓存。

嘿,我还没有看到是否有人遇到过和我一样的问题。

假设我在unstable_getStaticProps多条路线上有相同的页面:

1. /providers/[category]/[city] 
2. /providers/[category] 

两个页面的源代码相同,因此无需重复。 因此,对于第一个文件包含带有逻辑的源代码,第二个文件只导入第一个文件,如export { default } from './[city]';

但它抛出一个错误,即来自 getStaticProps 的数据未定义。 如果我将相同的代码硬拷贝到两个文件中,它就可以工作。

@homoky您需要重新导出这些方法:

export { default, unstable_getStaticProps } from './[city]';

我一直在尝试 SSG,但没有运气。

下面使用 v9.2.1 的代码是否会导致 SSG?

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.unstable_getStaticProps = async ctx => {
  return { props: { stars: 5 } }
}

export default Page

我从next build控制台输出显示:

Page                                                           Size     First Load
┌ ○ /                                                          354 B       72.1 kB
...
λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

@joostmeijles unstable_getStaticProps需要导出而不是附加到页面组件,例如

export const unstable_getStaticProps = async () => {
  return {
    props: { stars: 5 }
  }
}

@joostmeijles unstable_getStaticProps需要导出而不是附加到页面组件,例如

export const unstable_getStaticProps = async () => {
  return {
    props: { stars: 5 }
  }
}

谢谢,这就解决了。

如果有人想看到一个端到端的工作示例,使用全能路由和 SSG 创建动态页面(来自 CMS),请查看https://github.com/agility/agilitycms-next-starter- ssg。

我被难住了几次,并认为这可能对其他人有帮助。

在 zeit.co/now 上部署时,如何在构建期间使用getStaticProps访问下一个 API 路由? Isomorphic-fetch 需要一个绝对的 URL; 在本地它适用于http://localhost :3000 但不适用于现在部署(或者我做错了🤷‍♂️)。 有任何想法吗?

如果我是对的,API 路由将被部署为无服务器功能,我猜它们在构建过程中还没有准备好?

您需要直接调用 api 路由的函数,因为这比通过 http 的开销要少得多。

您需要直接调用 api 路由的函数,因为这比通过 http 的开销要少得多。

我可以在有关该主题的文档中阅读任何资源? 我正在迁移到 zeit.co/now :)

从字面上看,导入并调用函数:

import MyFunction from '../lib/somewhere'


export async function /* unstable_ */getStaticProps() {
  const result = await MyFunction()
}

另一个问题:是否可以并排使用getStaticProps / getStaticPathsgetServerProps ? 例如,如果我使用 SSG 预渲染了一些页面,但如果在 CDN 缓存中找不到,那么它将回退到 SSR 以按需生成页面?

getStaticProps将回退到 SSR 并将结果添加到缓存中,

getStaticProps将回退到 SSR 并将结果添加到缓存中,

@lfades ,如果我理解正确的话,那么我非常喜欢它,因为这意味着我可以预先渲染一些流行的页面,而不是提前查找并生成数千个页面。

但只是为了确保我理解...假设我有一个/products/[productId].js动态路径页面。 如果我提供getStaticProps和有限数量的结果getStaticPaths ,那么您是说如果在 CDN 缓存中找不到/products/123 (因为它不是) t in getStaticPaths ),它会回退到 SSR,运行getStaticProps ,然后将结果缓存为静态页面?

后续问题:如果我根本不提供getStaticPaths可以吗?

@flintinatux是的,是的👍

getStaticProps 将回退到 SSR 并将结果添加到缓存中

这是一个问题,因为无法执行 404,因为getStaticProps不允许更改res对象 - 如果函数调用期间出现错误,它将是 200 或 500。

这是计划改变吗?

@davidbailey00创建静态网站时,404 页面已经没有 404 状态代码。

当然,如果我进行完整的静态导出,则无法执行状态代码,因为一切都只是一个文件。 我正在谈论使用getStaticProps将混合站点部署到 ZEIT Now - 似乎它应该尊重getStaticPaths并提供 404 个页面,而不是强制呈现与动态路径匹配的所有页面,而不管这一点。

这不仅仅是它在 Now 上的工作方式,在next start

不过,我会重复之前所说的:这是实验性的,任何行为仍然可以改变。

但是可以使用getServerPropsgetInitialProps提供 404 个页面 - 如果getStaticProps getStaticPaths在考虑响应代码时忽略

我们可能会介绍更多处理状态代码的方法,但请记住,大多数静态站点(例如 CRA)将/*路由到index.html ,其中 404 仍然是 200。

大家好,我有一个直接的问题,我正在构建一个简单的网站,使用新的[unstable_]getStaticProps来 SSG 某些页面。 到目前为止,除amp外,一切正常。

如果页面包含[unstable_]getStaticProps ,则禁用amp 。 这是一个使用 next v9.2.1 的简​​单示例,您可以在其中检查:

import React from "react";
import { useAmp } from "next/amp";

export const config = { amp: `hybrid` };

const AmpExample = ({ date }) => {
  const isAmp = useAmp();
  return (
    <>
      <p>
        Welcome to the {isAmp ? `AMP` : `normal`} version of the Index page!!
      </p>
      <p>date: {date}</p>
    </>
  );
};
/**
 * If I get the dynamic data from getStaticProps,
 * page is SSG render but AMP is disabled when accessing
 * with `/ampExample?amp=1`
 */
export async function unstable_getStaticProps() {
  return {
    props: {
      date: new Date().toISOString(),
    },
  };
}

/**
 * If I get the dynamic data from getInitialProps,
 * page is SSR render but AMP is disabled when accessing
 * with `/ampExample?amp=1`
 */
// AmpExample.getInitialProps = () => {
//   return { date: new Date().toISOString() }
// }
export default AmpExample;

任何帮助了解如何让页面SSG与数据和amp工作?

嗨,如何支持getStaticProps App组件( _app.tsx )的

嗨,如何支持getStaticProps App组件( _app.tsx )的

@pkral78我可以告诉你我如何解决实际的开发状态。

我使用“布局作为高阶组件(HOC)”的方法创建了一个布局(不再在学习文档中🤷‍♂️)。

无论如何,我创建了一个如下的布局(只是一个例子):

import React from "react";
import Head from "next/head";

const withSSGLayout = Page => {
  const WithSSGLayout = props => {
    return (
      <>
        <Head>
          <title>My Web Page</title>
          <link rel="icon" href="/favicon.ico" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <link
            href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap"
            rel="stylesheet"
          />
        </Head>
        <Page {...props} />
      </>
    );
  };

  WithSSGLayout.unstable_getStaticProps = async () => {
    const pageStaticProps = Page.unstable_getStaticProps
      ? await Page.unstable_getStaticProps()
      : {};

    // Here you can make parent level queries too
    return {
      props: {
        ...pageStaticProps.props,
        parentProp: `dynamic prop-${new Date().toISOString()}`,
      },
    };
  };
  return WithSSGLayout;
};

export default withSSGLayout;

然后在您想要使用这种方法的页面中,您可以简单地添加 HOC(您必须明确导出[unstable_]getStaticProps和 amp 不能一起工作),但我发现了一种“不错的方式”来进行高级请求和每页 SSG 查询。

import React from "react";
import withSSGLayout from "../hocs/withSSGLayout";

export const config = { amp: `true` };

const Index = props => {
  const { date, parentProp } = props;
  return (
    <div>
      <h1>Example</h1>
      <h3>Local Prop?: {date}</h3>
      <h3>Parent Prop?: {parentProp}</h3>
    </div>
  );
};

// In theory you could do direct database queries
Index.unstable_getStaticProps = async () => {
  // Here you can make page level queries
  return {
    props: {
      date: new Date().toISOString(),
    },
  };
};
const IndexHOC = withSSGLayout(Index);

export const { unstable_getStaticProps } = IndexHOC;
export default IndexHOC;

如果这是一个很好的方法,我想低头。 在我的例子中,我使用这种技术来查询父页面中的链接和页面中的每页内容。 我希望它有帮助。

@robertovg您必须在模块级别导出,因为代码是摇树式的。 您对其建模的方式会导致将更多代码发送到客户端。

@timneutkens您能否为这个小例子提出更好的解决方案? 我只是想以某种方式同时使用“布局级别 SSG 查询”和“页面级别 SSG 查询”,我想到了这种 HOC 布局方法。

对我而言,主要限制是明确“导出 [unstable_]getStaticProps”,您需要在每个页面上将其标记为 SSG 页面。

我之前问过,我也非常感谢有关放大器 + SSG是否兼容的更多信息。

谢谢🙏

@robertovg首先,将布局与数据分开,因此对于共享布局,您将拥有如下简单的内容:

import Layout from '../components/layout'

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

然后对于getStaticProps使用来自另一个模块的方法获取共享数据,因此完整示例可能如下所示:

import fetchSharedData from '../lib/fetch-shared-data'
import Layout from '../components/layout'

export const unstable_getStaticProps = async () => {
  const sharedData = await fetchSharedData()
  const pageProps = {...}

  return {  props: { ...sharedData, ...pageProps } }
}

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

@robertovg首先,将布局与数据分开,因此对于共享布局,您将拥有如下简单的内容:

import Layout from '../components/layout'

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

然后对于getStaticProps使用来自另一个模块的方法获取共享数据,因此完整示例可能如下所示:

import fetchSharedData from '../lib/fetch-shared-data'
import Layout from '../components/layout'

export const unstable_getStaticProps = async () => {
  const sharedData = await fetchSharedData()
  const pageProps = {...}

  return {  props: { ...sharedData, ...pageProps } }
}

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

我看到并理解这个解决方案,但我试图提出的问题是如何扩展共享数据的使用。
例如,如果您有一个<Header /> ,它使用sharedData来获取链接,而这些链接来自 Headless CMS。 您必须使用道具或其他解决方案将<Header />作为<Layout />的子项注入。 并且您需要将<Header />注入到您要使用它的所有页面中。

使用HOC 方法,您只需在<Header />

这就是为什么我认为这是@pkral78提出的一个很好的观点,如果可能的

这就是为什么我认为这是@pkral78提出的一个很好的观点,如果可能的

这是在我的脑海里。 _app 页面应该有它的getStaticProps ,它在第一个页面渲染期间调用一次,然后将保存的props传递给下一个渲染页面。 但我仍在考虑这是否是正确的概念。

不确定这种事情是否是预期的用例,但它似乎不起作用:

// /pages/[...slug].jsx
import ReactDOMServer from "react-dom/server";

export async function unstable_getStaticProps({ params: { slug } }) {
  const filePath = "../content/" + slug.join("/") + ".mdx";
  const { default: Component } = await import(filePath);
  const content = ReactDOMServer.renderToStaticMarkup(<Component />);
  return {
    props: { title: slug.join(" "), content }
  };
}

export default function Page({ title, content }) {
  return (
    <div>
      <h1>{title}</h1>
      <div dangerouslySetInnerHTML={{ __html: content }} />
    </div>
  );
}

即使它不是预期的用例,它也会记录一个似乎有点可疑的错误:

[ warn ]  ./pages/[...slug].jsx
Critical dependency: the request of a dependency is an expression

编辑:

哦,好的,当我这样做时它会解决

const { default: Component } = await import(`../content/${slug.join("/")}.mdx`);

https://codesandbox.io/s/happy-oskar-40bug

这是在抱怨您的导入文件路径是动态的

在周四1月30日2020年00:29,扬Potoms [email protected]写道:

不确定这种事情
https://codesandbox.io/s/nifty-cache-jspqr是一个预期的用例,但是
它似乎不起作用:

// /pages/[...slug].jsximport ReactDOMServer from "react-dom/server";
导出异步函数unstable_getStaticProps({ params: { slug } }) {
// 这甚至有多安全?
const filePath = "../content/" + slug.join("/") + ".mdx";
const { 默认:组件 } = 等待导入(文件路径);
const content = ReactDOMServer.renderToStaticMarkup(Component);
返回 {
道具:{ 标题:slug.join(" "), content }
};
}
导出默认函数 Page({ title, content }) {
返回 (


{标题}




);
}

即使它不是预期的用例,它也会记录一个错误,似乎是
有点怀疑:

[警告] ./pages/[...slug].jsx
关键依赖:依赖的请求是一个表达式


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=AAADKRKOL34WKTG7J5QFRJ3RAIGPBA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXZHJK0200000000000000000000000000000000000000000000000001
或退订
https://github.com/notifications/unsubscribe-auth/AAADKRIWNA2DSMWFRGD453DRAIGPBANCNFSM4JRPBELQ
.

这就是为什么我认为这是@pkral78提出的一个很好的观点,如果可能的

这是在我的脑海里。 _app 页面应该有它的getStaticProps ,它在第一个页面渲染期间被调用一次,然后将保存的props传递给下一个渲染页面。 但我仍在考虑这是否是一个正确的概念。

@ pkral78 ,这可能是因为在我想象的大多数 SSG 站点中使用 Next 实现,我想要一个“公共部分”(页眉、页脚、侧边栏......)。 如果需要,为什么不直接在 _app 中查询该公共部分,并使其在子页面中可用,而不必在每个页面上手动进行。

我唯一担心的是,如果你把它放在_app.js ,根据页面的不同,我们不能有一个以上的“共同部分”。 有了原型设计的想法,我希望能够在布局中使用它,因为它允许我们根据要呈现的页面类型拥有多个布局,“这就是我调用withSSGLayout的原因我的 HOC,因为我计划不仅有 SSG 页面,还有 SSR 和完全客户端的页面,甚至不止一个 SSGLayout。如果 Layouts 也可以负责父getStaticProps方法,我就可以做到这一点。

无论如何,在 Next 中使用 SSG 将使其成为任何类型网站的工具🙌

@Janpot关于https://github.com/zeit/next.js/issues/9524#issuecomment -580012327

强烈建议不要import()使用动态路径。 它会将路径下的每个可能的文件捆绑到 JS 包中,并在这样做时大大降低构建性能。

@timneutkens当然,有道理。 getStaticProps仅用于查询外部 API,而不是文件系统?

@Janpot你可以从文件系统中读取,但通常你最终会查询一些外部 API。

@timneutkens好的,最好使用@mdx-js/runtime ,而不是依赖@next/mdx我猜。

import ReactDOMServer from "react-dom/server";
import { promises as fs } from "fs";
import MDX from "@mdx-js/runtime";

export async function unstable_getStaticProps({ params: { slug } }) {
  const mdxContent = await fs.readFile(`./content/${slug.join('/')}.mdx`, {
    encoding: "utf-8"
  });
  const content = ReactDOMServer.renderToStaticMarkup(<MDX>{mdxContent}</MDX>);
  return {
    props: { title: slug.join(" "), content }
  };
}

export default function Page({ title, content }) {
  return (
    <div>
      <h1>{title}</h1>
      <div dangerouslySetInnerHTML={{ __html: content }} />
    </div>
  );
}

@Janpot是的! 你也可以使用普通的 markdown,这就是我们为 nextjs.org/docs 所做的。

关于https://github.com/zeit/next.js/issues/9524#issuecomment -580207073,这与我目前使用 Next 和 SSR 完全一样。 我有一个在布局级别执行的 GraphQL 请求,其内容与应用程序的通用组件(导航栏、页脚和动态子项)共享。 然后,动态子节点通常会针对特定于页面的内容发出另一个 GraphQL 请求。

因此,有一种重新使用它的方法似乎很重要,我不想在每个页面上复制代码来获取那些公共数据。

嘿!
我在这里很新。 刚刚开始着手将应用程序迁移到 NextJS。

有一个基本用例将极大地受益于此功能 - 多语言版本。 我正在开发的 Web 应用程序有 16 种语言版本,每天有 100.000 多个页面浏览量,并且能够静态生成例如登录页面会很棒,但问题是路由。

使用服务器端渲染,我可以读取请求头或 cookie 并渲染正确的语言版本,但没有它,是为每个版本(如 /en、/de、/fr 和“/”)创建路径的唯一解决方案,让 NextJS 只做重定向?

在了解ReactDOMServer.renderToStaticMarkup我将其添加到我的unstable_getStaticProps函数中,我发现由于显着改善了交互时间和最大潜在首次输入延迟,我的(移动)PageSpeed 得分从 96 提高到 100 .

我可以在没有 JavaScript 的情况下访问该页面并且它加载正常,所以尽管使用 SSG,React 似乎正在处理页面加载。

也许这是我对 React 缺乏了解,但我希望使用和不使用 JavaScript 的性能是相同的,并且我不希望预渲染组件有帮助(我认为这就是 SSG 正在做的)。

是预期的,错误还是我做错了什么?

预提交: https : 2Fposts% 2Fgathered-1-0-1
提交: https :
提交后: https : &tab=mobile

@约瑟夫达菲

因此,尽管使用 SSG,但 React 似乎正在处理页面加载。

它正在滋润 DOM。 基本上:

  1. 您的浏览器在浏览器 DOM 中加载 SSR html
  2. React 重建整个虚拟 DOM
  3. React 遍历这些 DOM 并同步它们(hydration)

如果您的内容确实是静态的,例如没有副作用或事件处理程序,那么步骤 2. 和 3. 是不必要的。 使用您的方法,您基本上可以将组件树减少为具有 1 个属性的 1 个组件,这对于 React 渲染和水合非常快。 (+ dangerouslySetInnerHTM在水合过程中被忽略)

<div dangerouslySetInnerHTML={{ __html: props.htmlContent }} />

请记住,事件处理程序和副作用不适用于此方法。

编辑:

一个想法可能是允许在getStaticProps返回静态 html 时省略页面上的默认导出。 IE

export async function unstable_getStaticProps() {
  // ...
  return {
    props: { dangerouslySetInnerHTML: { __html: '<div>static content</div>' } }
  };
}

由于不需要在客户端呈现任何内容,next.js 可以从页面中排除其运行时,只需内联getStaticProps返回的 html。 它的工作方式与在 next.js 根节点上使用dangerouslySetInnerHTML方式相同。
我想这比部分水合作用更容易实现,尽管功能不那么强大。 在这里重用 React 本身的术语可以减少对该功能如何工作的混淆。

我正在尝试将静态站点迁移到 Next.js,并且我想将博客文章的所有 .html 变体重定向到不以 .html 结尾的版本。 似乎getStaticProps当前没有获取上下文,因此我无法检查传入的 slug 和重定向。 如果getStaticProps获得完整的上下文会很有帮助,这样我就可以用它做一些有条件的事情。

@nodabladam听起来您正在寻找自定义路由 RFC:#9081。

该 RFC 将允许您定义如下内容:

// next.config.js
module.exports = {
  redirects() {
    return [
      // Redirect from the old HTML version of a blog post
      {
        source: "/blog/:post.html",
        destination: "/blog/:post",
        permanent: true
      }
    ];
  }
};

您目前可以在experimental键下试用此功能:

// next.config.js
module.exports = {
  experimental: {
    redirects() {
      // ...
    }
  }
};

我已经在我的一个项目(大约 8K 页)上实现了 getStaticProps 和 getStaticPathNames。

但是,输出文件计入每次部署的 10K 文件限制。 使用 8K 页面,您将获得 16K 的输出文件,因为每个页面还获得一个 json 文件。

有计划增加这个限制吗? 或者我可以解决这个限制吗?

我也有同样的问题。
我知道他们希望解除这个限制,但我不知道什么时候会部署。

所以我在所有页面上使用 getStaticProps 并且只在其中一些页面上使用 getStaticPaths 并且它有效(我的产品页面生成了总页面的 70%,所以我没有在其中放置任何 getStaticPaths)。 我保持在限制之下但它并不完美,第一次加载很长并且难以处理 404 错误。

我也有同样的问题。
我知道他们希望解除这个限制,但我不知道什么时候会部署。

所以我在所有页面上使用 getStaticProps 并且只在其中一些页面上使用 getStaticPaths 并且它有效(我的产品页面生成了总页面的 70%,所以我没有在其中放置任何 getStaticPaths)。 我保持在限制之下但它并不完美,第一次加载很长并且难以处理 404 错误。

我希望他们尽快提高限制,但我希望它不会是 20K.. 从长远来看这对我来说还不够。

我想避免使用 getStaticPaths 的第一次加载时间.. 除了 Zeit Now 之外,我可能还需要寻找其他解决方案

Next.js 还将自动公开一个 API 端点,该端点返回调用 getServerProps 的结果。 [...] Next.js 将获取这个公开的 API 端点以获取 JSON 数据,该数据被转换为呈现页面客户端所需的道具。

Next.js 将在进行实际路由更改和呈现页面组件之前从该端点获取数据(它不能,至少在默认情况下,不能以任何其他方式执行)。 因此,由于某些页面是静态生成的,用户可能会体验到非常活泼的站点,但是如果他们单击指向 SSR 页面的链接,则站点会在路由更改之前突然“挂起”一段时间。

是否有推荐的方法来加载组件 _first_ 以便它可以填充加载指示器、动画占位符等? (而不是将它们添加到当前页面。)如果不是,它是否与新提出的功能相关? 我在 render 方法中使用 getInitialProps 和 hooks 的组合来实现它,但感觉很混乱。

我认为这种 UX 模式(即时页面切换)是许多人(大多数?)的首选,但我还没有看到使用 Next.js 的任何示例。 我只使用了几天的框架,所以如果我错了,请纠正我。

对新功能真的很兴奋! 谢谢你的工作。

@nicoqh ,您对页面转换的担忧并非特定于 SSG,因为挂起发生在当前的getInitialProps 。 我使用nprogress至少在加载下一页时在顶部显示一个进度条,但我也看到了这个具有合法页面转换的示例,听起来更接近您所描述的内容。 我自己还没有尝试过,但我希望它对您的需求有所帮助:
https://github.com/zeit/next.js/tree/canary/examples/with-next-page-transitions

看起来返回的 json 文件/_next/data/BUILD_ID/<file>.json不支持 assetPrefix。 这导致文件在我的生产环境中变为 404,因为我有一个设置,期望所有 _next 都是通过 CDN 的资产。 这些 json 文件最终应该通过资产前缀 (CDN) 进行路由,对吗?

我也有同样的问题。
我知道他们希望解除这个限制,但我不知道什么时候会部署。
所以我在所有页面上使用 getStaticProps 并且只在其中一些页面上使用 getStaticPaths 并且它有效(我的产品页面生成了总页面的 70%,所以我没有在其中放置任何 getStaticPaths)。 我保持在限制之下但它并不完美,第一次加载很长并且难以处理 404 错误。

我希望他们尽快提高限制,但我希望它不会是 20K.. 从长远来看这对我来说还不够。

我想避免使用 getStaticPaths 的第一次加载时间.. 除了 Zeit Now 之外,我可能还需要寻找其他解决方案

@erhankaradeniz@ziltosh我们应该很快就会推出。 如果您想尽快获得帮助,您可以直接 ping 我或[email protected] ,他们会为您解决问题。

我也有同样的问题。
我知道他们希望解除这个限制,但我不知道什么时候会部署。
所以我在所有页面上使用 getStaticProps 并且只在其中一些页面上使用 getStaticPaths 并且它有效(我的产品页面生成了总页面的 70%,所以我没有在其中放置任何 getStaticPaths)。 我保持在限制之下但它并不完美,第一次加载很长并且难以处理 404 错误。

我希望他们尽快提高限制,但我希望它不会是 20K.. 从长远来看这对我来说还不够。
我想避免使用 getStaticPaths 的第一次加载时间.. 除了 Zeit Now 之外,我可能还需要寻找其他解决方案

@erhankaradeniz@Ziltosh我们应该很快就会推出。 如果您想尽快获得帮助,您可以直接 ping 我或[email protected] ,他们会为您解决问题。

谢谢@kvangundy
我已经就这个问题在 Twitter 上联系过你 ;-)

@erhankaradeniz你能发邮件给[email protected]吗? 这样它就会正确地在我们的系统中结束。

@flintinatux ,感谢您的提示。 我看过这个例子,它在加载数据之前加载页面组件没有帮助,所以页面内占位符等是不可能的。 不过,这是一个有趣的例子,谢谢!

我想它不会在这个问题中得到解决,这意味着它偏离了主题,所以我会找其他地方讨论它:)

我认为将 getInitialProps 拆分为getStaticPropsgetServerProps方法要干净得多! 我确实有一个关于这如何影响我们的用例的问题:
我们想要创建 2 个单独的构建:一个用于我们的生产站点的静态版本,一个使用 SSR 用于编辑环境的版本。

我想我可以根据构建有条件地附加getStaticPropsgetServerProps作为静态方法(类似于 https://github.com/zeit/next.js/issues/9524#issuecomment- 558617056),但我不确定这是否可以有条件地按原样导出它们。 有什么想法可以根据构建支持动态/静态吗?

关于:

  • 加载状态: https :

    • 现在正在工作 (#10424)。

  • 预览: https :

    • 正在处理中,稍后开放PR。

RFC 将更新以反映稍后的变化,仍然在我们的应用程序中迭代实际使用。

我想知道是否有一种方法可以使用某种通配符路由来捕获构建时未知的路由。 我可以从例如 CMS 数据呈现静态页面真是太棒了,但是如果有人添加了新项目怎么办? 我没有一个静态页面。 这个问题困扰了我很长时间。

我已经设置了动态路由来呈现静态页面 _pages/[slug].js_。 _getStaticPaths_ 正在获取我想要静态呈现的所有页面。 我有 _getStaticProps_ 来查询数据并将其传递给渲染函数。 _getStaticPaths_ 中给出的所有页面都在构建时呈现为 _.next/server/static_ 中的 HTML 文件。 伟大的!

现在我运行npm run start和这些页面。 但是请求丢失的 url(如 _/foo_)会在 _.next/server/static_ 中生成新的静态 HTML 和 JSON 文件。 这是不好的。 如何让服务器将所有其他 url 重定向到 _pages/_error.js_?

https://github.com/zeit/next.js/issues/9524#issuecomment -582777067

我们也在报道这一点。

现在我运行 npm run start 和这些页面。 但是请求丢失的 url(如 /foo)会在 .next/server/static 中生成新的静态 HTML 和 JSON 文件。 这是不好的。 如何让服务器将所有其他 url 重定向到 pages/_error.js?

截至目前,这仍在进行中,并非意外行为。

再次提醒您,您正在使用一项实验性功能,行为随时可能发生变化。 当它不稳定时使用它时,事情会发生变化并可能会在所有版本之间中断。

@timneutkens谢谢! 我理解不稳定。 你知道如何管理这个吗? 浏览代码并注意到在 _unstable_getStaticProps_ 中抛出错误会呈现错误页面。 这可能是一个不错的方法。 我只需要一种方法将错误传递给 _pages/_error.js_。 我想发送 404。现在是 500。

我之前在其他线程中发布了很多次,但是“转到 _error”是意外行为,截至目前,您的页面应该呈现 404 状态。 简单地说if(!data.something) { return <My404Component /> } ,然后My404Component应该设置noindex元标记。

真的吗? 文档明确指示将 _pages/_error.js_ 用于 404。

请参阅: https :

@jiv-e 是由以下原因引起的 404:

  • 找不到网页
  • 文件未找到

如果您有动态路由,则必须像我说的那样处理“404”情况,例如https://nextjs.org/docs/advanced-features/custom-error-page#reusing -the-built-in-error-页

知道了! 谢谢!

我想使用getStaticProps在构建时获取翻译/语言键,因为它们很可能每月甚至每年更改 1-2 次。 也不需要它们作为 DOM 中的 JSON/props。 问题是我不想将键沿着树传递给我实际使用它们的组件 - 哪些方法适合我的用例?

useTranslation() 挂钩(或 HOC)与上下文?

如果AppTree是 NextGetStaticProps 上下文 ( getStaticProps({ AppTree }) ) 的一部分,那就太好了。 否则就不可能在 ssg 上运行类似 apollos getDataFromTree东西。

在这一点上,我们不打算在 getStaticProps 中允许 AppTree 遍历,因为它对性能非常不利(来自公司的一致反馈)。 当您将 getStaticProps 添加到页面时,它仍会通过 _app 的 getInitialProps 以允许增量采用,因此它仍然可以真正与 Apollo 一起使用。

如果我们可以同时拥有amp: 'hybrid'SSG功能,那就太好了。
这可以通过为这样的页面创建两个文件来实现,即:

  • (SSG) index.html
  • (AMP) index.amp.html

这将允许代理根据?amp=1查询参数解析为 amp 文档。

如果我们可以同时拥有amp: 'hybrid'SSG功能,那就太好了。
这可以通过为这样的页面创建两个文件来实现,即:

  • (SSG) index.html
  • (AMP) index.amp.html

这将允许代理根据?amp=1查询参数解析为 amp 文档。

正是@Dacturne ,这是我看到的唯一缺点,因为我之前在此线程中发表评论时已经开始在项目中使用 SSG。

🤞

@jansedlon我写了一篇博文来回答你的问题:

我想知道是否有一种方法可以使用某种通配符路由来捕获构建时未知的路由。 我可以从例如 CMS 数据呈现静态页面真是太棒了,但是如果有人添加了新项目怎么办? 我没有一个静态页面。 这个问题困扰了我很长时间。

https://paqmind.com/en/blog/ssr-is-not-the-future

(因为太大了就不在这里发了)

@ivan-kleshnin 我快速浏览了一下,它看起来非常令人兴奋! 你可能已经为我节省了数百小时! 非常感谢,今天晚些时候我会更深入地研究。

https://github.com/zeit/next.js/issues/9524#issuecomment -582799948

@jansedlon如前所述,我们正在研究 @ivan-kleshnin 的博文中未涵盖的内容。 希望很快就能分享更多关于这方面的信息。

@timneutkens喜欢到目前为止的变化🙏您有任何计划来改进/支持完全静态+国际化吗?

在将 tinacms.org 从 Gatsby 迁移到 Next.js 的过程中,我们一直在使用新的getStaticProps / getStaticPaths API,到目前为止,效果非常好!

我们遇到的一个绊脚石是生成 RSS 提要。 理想情况下,我们希望静态生成它,因为它引用的内容是静态生成的。 我目前没有看到这样做的方法,因此我们只是通过查询内容并将 XML 写入响应来在服务器端处理它。

是否有任何关于支持非 HTML 内容类型的静态生成的讨论?

仅供参考,我们现在开始在 zeit 上使用getStaticProps并使用--prod标志发布,并且没有为新版本上的 json 文件清除缓存。 将我们的生产版本切换回使用别名功能有效并且缓存被清除。

在将 tinacms.org 从 Gatsby 迁移到 Next.js 的过程中,我们一直在使用新的getStaticProps / getStaticPaths API,到目前为止,效果非常好!

我们遇到的一个绊脚石是生成 RSS 提要。 理想情况下,我们希望静态生成它,因为它引用的内容是静态生成的。 我目前没有看到这样做的方法,因此我们只是通过查询内容并将 XML 写入响应来在服务器端处理它。

是否有任何关于支持非 HTML 内容类型的静态生成的讨论?

我是为自己考虑的,我刚刚发现了这一点。 这是我的脚本:

"scripts": {
    "dev": " next",
    "build": "yarn sitemap && next build",
    "start": "next start",
    "sitemap": "ts-node --project ./cli/tsconfig.spec.json ./cli/generateSitemap.ts"
  },

next build被称为yarn sitemap ,它会生成静态站点地图。 您可以使用相同的技术,例如将所有数据缓存到 json 中,您将需要在getStaticProps中使用它,并且您可以在多个页面上重用它。

更新了 RFC,稍微改变了getStaticPaths行为(你现在需要返回一个paths键,这反映了getStaticProps必须返回props 。这个Next.js 中还没有发生变化。

还添加了对fallback行为的解释(按需后台生成在构建时未导出的页面)。

对 RFC 进行了另一次更新,添加了有关Loading状态的客户端导航更改的解释。

我们可能想添加一种方法让用户知道加载状态是否通过 React 钩子呈现 🤔

好东西! 我只是想知道,有没有办法让静态生成的页面使用单个 JSON 文件在多个路由之间共享数据(如代码拆分但用于数据)?

我遇到了最新的canary版本,并立即被新的Loading状态所困扰。 在过去,在视图层开始渲染之前安全地假设我已经获得了正确的数据是很好的。 强制异步加载与此大相径庭。 我真的很喜欢删除新的自动生成的 SSR 端点将替换的所有样板端点,但我不打算重新设计每个页面以包含新的Loading状态。

我理解对更快 TTFB 的渴望,并且在未来这可能是我的应用程序的一个不错的选择。 但是是否有可能使Loading状态成为选择加入选择退出的功能,类似于fallback: falsegetStaticPaths ? 可能是页面上的export const enableLoadingState = false ,或者next.config.js中的站点范围。

https://github.com/zeit/next.js/issues/9524#issuecomment -583962425

再次提醒您,您正在使用一项实验性功能,我们目前正在试验该行为。

我将我的(实验性)SSG 网站部署到 Now(使用默认设置)。 它工作正常,但我在浏览网站时在网络选项卡中看到 404 错误。 所有 404 错误都指向_next/static/pages/[slug].js

这是实验性的预期行为吗? 还是我应该更改一些设置?

@joostmeijles听起来您没有向href提供正确的as next/link 。 对于动态页面, href需要是页面href='/[slug]'并且as需要是 URL as='/slug-1'

我在构建期间在控制台中收到 3 个日志,这是一个错误吗?

// Page is showing three logs despite static path only having 2 entries and output generating only two files as intended
export default function Page(props){
    console.log("Page - should only show twice", props); 
    return <><h1>Page</h1></>
}

export async function unstable_getStaticProps(props) {
    console.log("unstable_getStaticProps - should only show twice", props);
    return {
      props
    };

}

export async function unstable_getStaticPaths() {
    console.log("show once")
    return {
        paths: [
        { params: { year: "1901" } },
        { params: { year: "1902" } },
        ]
    }
}

不,按照 RFC 中的fallback预期。

不,按照 RFC 中的fallback预期。

export async function unstable_getStaticPaths() {
    console.log("show once")
    return {
        fallback: false,
        paths: [
        // This renders /blog/hello-world to HTML at build time
        { params: { year: "1901" } },
        { params: { year: "1902" } },
        ]
    }
}

我尝试选择退出,但出现此错误。

错误:从 /[year] 中的不稳定_getStaticPaths 返回的额外键(回退)当前允许的唯一字段是paths

再次提醒您,您正在使用一项实验性功能,我们目前正在试验该行为,但并非所有内容都已实施。

此功能getStaticProps仅适用于页面?
应用程序/文档也会很有趣,例如为应用程序获取一些全局配置?

我已经“成功”实现了这一点,到目前为止我对结果很满意..但我想知道有没有办法让后续构建“更快”? 例如检查 SSG 生成的页面是否没有更改并且不重新生成这些页面? (可能是我的一厢情愿)

@timneutkens是否有计划为 SSG 页面添加 sitemap.xml 生成器? 我什至不谈论动态路由,因为我认为现在只为静态页面实现它更容易。

@timneutkens是否有计划为 SSG 页面添加 sitemap.xml 生成器? 我什至不谈论动态路由,因为我认为现在只为静态页面实现它更容易。

是的,这将是一个不错的选择。 目前自己用 SSR 生成一个。 (但 sitemap.xml 文件需要很长时间才能加载)

https://github.com/zeit/next.js/issues/9524#issuecomment -585293270

最初仅用于页面,因为在 getStaticProps 着陆后会有其他工作影响它。

https://github.com/zeit/next.js/issues/9524#issuecomment -586957539

是的,但不作为此 RFC 的一部分。 着陆后会有后续行动。

@timneutkens我认为 SSG 页面的实现很简单,因为您可以在每次 Next 构建静态页面时将 URI 推送到数组中,然后,当它结束时,只需将数组映射到每个 XML 标记中,加入并将其插入中间<sitemapindex>标签。 getStaticProps在返回对象中可以有另一个名为excludeFromSitemap因此默认情况下所有页面都包含在sitemap.xml但可以选择退出。

如果是这种情况,开发人员可以很好地控制哪个静态页面将进入站点地图(例如:如果页面[foo]getStaticPaths函数返回带有foo路径'abc''xyz'但只有'abc'文件应该在站点地图中,开发人员可以将excludeFromSitemaptrue如果getStaticProps的参数==='xyz' getStaticProps

此外,对于 SSR 和静态页面,可以从页面文件中导出常量(即export const excludeFromSitemap = true; ),就像getServerPropsgetStaticPathsgetStaticProps被导出。

在 SSG 页面中,如果存在导出的excludeFromSitemap常量(页面默认值)并且该键也在getStaticProps函数返回的对象中(特定于路径),则导出的值应作为默认值该页面中所有路径的值和特定于路径的excludeFromSitemap ,当存在于getStaticProps对象中时,应该覆盖页面的默认值(因此页面可以执行export cosnt excludeFromSitemap = true然后将excludeFromSitemap键添加到从getStaticProps返回的对象中,其值为false以从站点地图中排除除特定路径之外的所有路径)。

附加到数组的代码将是这样的(我计算了真值表并使用卡诺图获得了最小布尔表达式):

//...somewhere else
const validExcludeFromSitemapTypes = ['boolean','undefined'];

//...for each path
const isSSG = !!getStaticPropsReturnedObj && typeof getStaticPropsReturnedObj === "object";
if(
    validExcludeFromSitemapTypes.indexOf(typeof pageExports.excludeFromSitemap)<0 ||
    (isSSG && validExcludeFromSitemapTypes.indexOf(typeof getStaticPropsReturnedObj.excludeFromSitemap)<0)
) {
    throw new Error("'excludeFromSitemap' can either be ommited (undefined) or be a boolean");
}
const defaultExcludedValue = !!pageExports.excludeFromSitemap;
const hasSpecificExcluded = isSSG && typeof getStaticPropsReturnedObj.excludeFromSitemap !== "undefined";
const specificExcludedValue =  isSSG ? !!getStaticPropsReturnedObj.excludeFromSitemap : false;

if(!specificExcludedValue && (!defaultExcludedValue || hasSpecificExcluded))
    sitemapURIs.push(correctlyEncodedURI);

将数组转换为站点地图就像这样做一样简单(假设数组中的 URI 已经被!excludeFromSitemap编码和过滤):

function createSitemap(sitemapURIs: string[]): string {
    return `<sitemapindex>${sitemapURIs.map(u=>`<sitemap><loc>u/loc></sitemap>`).join('')}</sitemapindex>`;
}

我认为这个功能在 Next.JS 中很合适,因为它的部分任务是为用户提供 100 的 SEO 分数,而拥有sitemap.xml将有很大帮助! ( robots.txt也可能生成,将else添加到将路径添加到站点地图数组的条件中,以将该路径附加到另一个不允许的页面数组中)

在当前版本中,当unstable_getStaticPathsunstable_getStaticProps函数一起使用时,您不能对/api/函数进行 api 调用。
由于服务器没有运行,因此无法以这种方式发出相应的请求并生成静态道具。
你要么不提供路径函数(这基本上使这个 SSR 带有缓存,这仍然很好!)或者依赖 SSR 而不是 SSG。

也许这会是这个功能的一个很好的补充? 我不确定这里最好的方法是什么,我在其他地方读过一个提案,建议使用 SSR 和/api路由缩短 http 请求,这在这里也很方便。

但所有这些当然意味着在构建环境中运行代码,这将调用其他服务/数据库调用或类似的。 这在实施时应该清楚,但对于此功能来说,这将是一个很酷的补充。

@reckter 是的,我自己也做了类似的事情。 在静态生成每个单独的页面请求时,我必须连接到我的数据库。 觉得很奇怪...

我希望这不是最终用例

拥有某种可以从 next.config 或其他内容设置的初始化脚本会很好...

@reckter一种将 HTTP 请求快捷方式从 SSG/SSR 发送到 API 路由的方法会非常好! 在这两种情况中的任何一种情况下,向自己发出网络请求都感觉很奇怪。

无论如何,在 SSG 期间访问 API 路由的可能解决方案是在编译静态页面之前让本地服务器只运行/api路由! 所以构建步骤将是:

  1. 启动一个只为/api路由提供服务的服务器(可能称为“api 编译服务器”或类似的东西)
  2. 运行unstable_getStaticPaths
  3. 运行unstable_getStaticProps
  4. 编译静态页面

@reckter基本上你不必调用 API 路由,你可以直接调用它实现的函数,这也避免了很多由于 http 导致的开销。

基本上,如果您目前有一个如下所示的 API 路由:

import myDb from 'mydatabaseprovider'
const db = myDb()

export default async (req, res) => {
  cont myData = await db.query('posts')
  res.json(myData)
}

您将其更改为:

import myDb from 'mydatabaseprovider'
const db = myDb()

export async function getData() {
  const myData = await db.query('posts')
  return myData
}

export default (req, res) => {
  const myData = await getData()
  res.json(myData)
}

然后在您的页面中:

import {getData} from './api/myfunction'

export async function getStaticProps() {
  const myData = await getData()
  return {
    props: {
     myData
   }
  }
}

对 GraphQL API 做同样的事情会很棘手。 也适用于大多数 REST。

API 调用 != 从数据库中获取(一般情况下)
API 层几乎总是有一些业务逻辑,如字段重命名、数据重新格式化等。

我相信你有理由禁止pages/api调用……但是绕过真正的 API 并不容易或便宜。 几毫秒的空闲时间不会超过额外代码/复杂性 IMO 的费用。

此外,允许对任何 API 的请求也感觉很奇怪。 除了你自己的🤷‍♂

使用unstable_getStaticPaths会导致页面重新加载,例如在 redux 中丢失当前状态。 这种行为将来会改变吗?

编辑:似乎可以通过在链接或路由器中使用as选项来规避这种行为

<Link
  href='/item/[key]'
  as={`/item/${itemName}`}
>
router.push(
  '/item/[key]',
  `/item/${itemName}`
);

@meesvandongen一直都是这样。 如果您的<Link>无效,它会将您带到后端部分,基本上作为<a> 。 像[key]这样的动态片段必须与相应的值配对。

@reaktivo pages/[lang]/blog/[id].js -> 在getStaticPaths提供所有静态渲染的 url。

https://github.com/zeit/next.js/issues/9524#issuecomment -562625858
在这种情况下,它需要为除 index.js 之外的每个页面添加getStaticPathsgetStaticProps函数。
如果有一些mdx页面,项目维护起来比较困难

考虑更改或兼容静态getStaticPaths getStaticProps方法。 https://github.com/zeit/next.js/issues/9524#issuecomment -558617056
如果是这样,页面可以被高阶函数或高阶组件(HOC)包裹。
这样代码更易于维护,也更方便打字稿。


摇树与动态。 多么令人头疼的权衡。😂

使用9.2.3-canary.13我尝试在 getStaticPaths 中使用fallback: false ,如下所示:

  return {
    fallback: false,
    paths: slugs.map(slug => ({params: {slug: slug}}))
  }

但它失败并出现以下错误:

Error: Extra keys returned from unstable_getStaticPaths in /blog/[slug] (fallback) Expected: { paths: [] }

使用9.2.3-canary.13我尝试在 getStaticPaths 中使用fallback: false ,如下所示:

  return {
    fallback: false,
    paths: slugs.map(slug => ({params: {slug: slug}}))
  }

但它失败并出现以下错误:

Error: Extra keys returned from unstable_getStaticPaths in /blog/[slug] (fallback) Expected: { paths: [] }

我认为您需要更高级别的地图,因此 map 返回您当前拥有的对象,但具有独特的 slug。 而不是在路径中映射。

我还没有在 nextjs 上更新我的版本,但它应该是相似的:

return data.map(item => {
    return {
      params: {
        slug: item.slug,
      },
    }
  })

@jorngeorg这是一个公开的公关: https :

了不起的贡献! 它确实改进了静态渲染过程。

我建议添加到动态路由的文档中,将在不调用getStaticProps的情况下生成“回退” - 这意味着您必须对组件进行编码以解决 props 为空的情况。

或者,您可以在创建回退时更改行为以在没有上下文的情况下调用getStaticProps 。 这将与next export当前的工作方式一致(例如,通过在没有上下文的情况下运行getInitialProps /p/[id].js导出到/p/[id].html )。

  • getStaticProps - 在next build时间选择加入静态生成 (SSG)。
  • getServerProps - 选择加入按需呈现的服务器端呈现 (SSR)。

10722

将 getServerProps 重命名为 getServerSideProps。

我建议添加到动态路由的文档中,将在不调用getStaticProps的情况下生成“回退” - 这意味着您必须对组件进行编码以解决 props 为空的情况。

好点的提一下! 我也有一些构建/部署错误,因为我错过了。

更新了 RFC 以反映更改

@timneutkens

  • 对同一路径的后续请求将服务于生成的页面

我认为这意味着 Next.js 将缓存生成的页面? 这是内存缓存吗? 这个缓存是受限制的还是会导致内存泄漏?

当您使用next start它使用类似于当前缓存示例的 lru-cache,当前默认限制为 50MB,我们可能会稍后对其进行配置: https :

当您在 ZEIT 上托管时,现在生成和缓存发生在 CDN/代理上,因此它的工作方式略有不同,您无需担心内存泄漏或是否超出了 lru 限制。

👍 好吧,似乎有道理。 这或多或少是我认为的一种明智的默认行为。

  • getStaticProps - 在next build时间选择加入静态生成 (SSG)。
  • getServerProps - 选择加入按需呈现的服务器端呈现 (SSR)。

10722

将 getServerProps 重命名为 getServerSideProps。

为什么要重命名? 恕我直言,getServerProps 足够准确且输入时间较短,添加 Side 对我来说是多余的。

我想知道是否对 getStaticPaths 方法进行了任何更改? 我的动态页面不再作为静态页面生成,它们现在作为 lambda 函数导出?

当现在的默认行为是页面首先呈现为 lambda 并且仅在访问特定页面后,页面才会生成为静态页面时,我是否正确? (就像在后备中提到的那样)

@erhankaradeniz没有对getStaticPaths任何会导致您的页面成为 Lambda 的更改。 这很可能是使用错误。

您能否显示您的代码以便我们确定问题?

@Timer现在我已经恢复到[email protected] ,在那里我仍然可以使用参数,直到我弄清楚为什么它不能使用路径。

这就是我目前生成路径的方式:

return cityData.map(city => {
    return {
      params: {
        country: city.countrySlug,
        city: city.slug,
      },
    }
  })

在另一页我做:

return cityData.map(city => {
    return {
      params: {
        country: city.countrySlug,
        city: city.slug,
      },
    }
  })

尚未设法将其转换为带有路径的新 Canary 版本。 我一定是做错了什么,因为 console.logs 甚至没有在getStaticPath内触发

我在嵌套路径预渲染和 SSG 方面遇到了麻烦:

// pages/[lang]/[...slugs].js

export async function getStaticPaths() {
  let knex = await import("knex/client").then(m => m.default)
  let pages = await knex("page").select(["lang", "url"])
  return {
    fallback: true,
    paths: pages.map(page => {
      return {
        params: {
          lang: page.lang,
          slugs: page.url == "/" ? [] : page.url.slice(1).split("/"),
        }
      }
    }),
  }
}

造成

Error occurred prerendering page "/en/". Read more: https://err.sh/next.js/prerender-error:
Error: The provided export path '/en/' doesn't match the '/[lang]/[...slugs]' page.

用于主页。 由于某种原因 NextJS 无法匹配

{lang: "en", slugs: []}

/[lang]/[...slugs]

如果我提供{lang: "en", slugs: ["/"]}它会构建,但 URL 错误:

├ ● /[lang]/[...slugs]      875 B        204 kB
├   ├ /en/credits
├   ├ /en/%2F

作为记录, getServerSideProps在类似的设置下工作正常。

我知道这是实验性的,但这个线程是为了提供反馈,对吧?

pages/[lang]/[...slugs].js匹配/en/abcdef而不是/en ,为此您目前必须创建pages/[lang]/index.js

为此开放了一个功能请求: https :

首先,这太棒了。 我一直希望在 Next.js 中有这样的东西,这样我终于可以摆脱 Gatsby.js 并拥有一个混合应用程序(静态 + 动态)。

🚀 我试过金丝雀和半成品复杂的应用程序版本工作正常。 我承认我还没有阅读这里的所有评论,但不确定是否已经实施了摇树。

🤔 getStaticPaths感觉更像是setStaticPaths ,我们在其中定义了 SSG 行为的静态路径。 这让我有点困惑。

🧐 我想知道我们是否可以通过构建类别来缩短构建时间? 我知道这会使设置复杂化,但非常值得。 让我解释:

如果我们有像setBuildCategory这样的东西,将它设置为blogpages或任何人想要的2020-content 。 然后 SSG 构建器查找已更改页面的类别,并仅尝试从缓存 + 新渲染的组合中重建该类别。 像这样的东西可以帮助我们加快 SSG 并避免大量构建时间,因为这些东西不容易发生很大变化,但仍然可能发生变化,因此无法存档。

如果这有道理; 很高兴接听电话并讨论这个问题。

如何使用自定义服务器实现处理getServerSideProps

if (pathname === '/a') {
  app.render(req, res, '/b', query)
}

在上面的示例中,访问/a将呈现页面pages/b.js 。 但是客户端重定向到/a尝试下载a.json文件,在这种情况下不存在。

我们是否应该对/_next/data/{BUILD_ID}/{PAGE}.json请求具有类似的条件来呈现不同的 JSON 文件?

对于在 getStaticPaths 中使用fallback: true ,如何获取 req 对象? 目前看来我不能。 我需要它的原因是从浏览器中获取一些 cookie 来验证路由

@tylermcrobert你怎么想象在没有请求的情况下抓取饼干?!
根据“静态”和“动态”的定义,不能将具有后端取决于真实访问者请求的路由设为静态。 并不是说您不能将静态和身份验证结合起来......它只是身份验证部分将属于 API 和客户端代码而不是页面。

如何使用自定义服务器实现处理getServerSideProps

if (pathname === '/a') {
  app.render(req, res, '/b', query)
}

在上面的示例中,访问/a将呈现页面pages/b.js 。 但是客户端重定向到/a尝试下载a.json文件,在这种情况下不存在。

我们是否应该对/_next/data/{BUILD_ID}/{PAGE}.json请求具有类似的条件来呈现不同的 JSON 文件?

Next.js 支持动态路由参数,因此很少需要在自定义服务器中重新映射: https ://nextjs.org/docs/routing/dynamic-routes

您已经概述的方法不适用于<Link> (会导致整页转换),因此 getServerSideProps 已经可以工作。

@tylermcrobert你怎么想象在没有请求的情况下抓取饼干?!
根据“静态”和“动态”的定义,不能将具有后端取决于真实访问者请求的路由设为静态。 并不是说您不能将静态和身份验证结合起来......它只是身份验证部分将属于 API 和客户端代码而不是页面。

也许我误解了这种情况下的后备选项。 您所说的在构建时上下文中完全有意义。

没有预定义路线时不是fallback: true吗? 在那种情况下,会从浏览器到达回退,不是吗?

@tylermcrobertfallback: true案例有一个请求,但 API 必须由“最低公分母”统一。 我无法想象一个工作系统,其中所有内容都使用一组前提构建,然后使用一组完全不同的前提进行增量更新。 支持将是一场灾难。

我认为您忽略了这些增量构建仍将在构建之间缓存的观点。 因此,第一个访问者的角色将影响所有后续用户的构建结果! 听起来是个坏主意。

@ivan-kleshnin 我理解并且当然同意。 我问的原因是因为我的特定用例。

我正在使用允许预览功能的无头 CMS,因此在构建时将不包含需要预览的页面(因为此时正在预览的条目将不存在)。 我认为这是回退选项出现的情况。

要访问该预览,我需要访问通过 cookie 提供的 api 预览参考。

这是我应该完全废弃useStaticProps吗? 我不想失去静态构建的好处,因为我无法预览我的文档。

这个 RFC 对 gatsby 之类的东西的吸引力在于它为我们提供了静态站点生成的“混合控制”,这使得使用无头 CMS 变得不那么痛苦

我正在使用允许预览功能的无头 CMS,因此在构建时将不包含需要预览的页面(因为此时正在预览的条目将不存在)。 我认为这是回退选项出现的情况。

敬请期待,更早🕵

因此,如果我理解正确,我们可以在例如在我的情况下用户注册时使用 fallback true(由于它是新页面/用户,因此不会生成静态页面)但是当配置文件被访问时它会自动生成?

埃尔汗·卡拉德尼兹
http://www.erhankaradeniz.com

在2020年3月4日,在20:25,添Neutkens [email protected]写道:


我正在使用允许预览功能的无头 CMS,因此在构建时将不包含需要预览的页面(因为此时正在预览的条目将不存在)。 我认为这是回退选项出现的情况。

敬请期待,更早🕵


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看,或取消订阅。

用户数据是一个不好的例子,因为您想要获取该客户端。 回退用于按需静态生成在构建时尚未生成的页面。 例如,您可能希望在构建时生成前 100 篇博文,而不是生成其他流量较少的博文。

文档很快就会出现。

是的,我的意思是占位符页面。我确实会在客户端获取用户数据。

@timneutkens有没有办法删除或重建特定的静态生成页面?

你好!!! 听起来像是最佳应用。 我喜欢 React 和 Next !!! 让一切变得如此优雅和简单,供我们使用!! 但该示例包括概念博客。 我想在查询 Headless CMS 时看到一个实现示例,并将每页/帖子的提取作为静态项目导出。

// 欢呼,因为快到星期五了!!!

@timneutkens这太令人兴奋了👌

我们经常遇到的一个场景,除了动态路由或在循环中生成项目之外,我还没有完美的解决方案:next.js 或 gatsby:

由于历史原因,我们必须处理多个域(并且没有兴趣改变这一点),这些域提供相同/完全相同的页面,但定价、货币、支持电话号码和语言选择器除外。 本质上,这些营销页面中的大多数都是静态的,每天或每周构建它们就足够了(而不是让它们在每个请求上呈现)。

我的问题/想法:你看到一种方式(在未来?) getStaticPaths可以基于不是路由参数的东西生成页面,但可以在请求级别使用它们在它们之间切换(例如无服务器函数返回基于locale静态预构建结果)

具体来说,这意味着https://mysite.com/my-producthttps://mysite.co.uk/my-product将提供两个不同的静态页面,但我们不必生成 50 倍的下一个应用程序,也不必每次请求都点击 CMS 😅

在此先感谢并渴望听到您的想法,尤其是如果这是可以解决/解决的未来问题❤️

我正在考虑一个用例,我想将 SSG 用于 SEO 的高流量登陆页面和减少服务器负载,但仍希望在水合后使用当前数据,并在客户端路由到此页面。 那可能吗?

所以基本上在客户端路由到这个页面时,行为应该像getInitialProps (在页面变得可见之前获取当前数据)。 在服务器端路由到这个页面时,静态 html 应该被提供和水合,然后(可选)获取一些 api 响应以更新页面上的一些数据。

我只是玩unstable_getStaticProps只是为了尝试一下,我遇到了一个有趣的冲突:很难将 API 路由与getStaticProps

不要关注代码的语义,只关注数据获取流程:

// pages/api/healthcheck.ts
import { NextApiResponse, NextApiRequest } from 'next';

export type ApiHealthCheckResponse = {
  message: 'ok';
};

const healthCheckHandler = (
  req: NextApiRequest,
  res: NextApiResponse<ApiHealthCheckResponse | ''>,
) => {
  if (req.method === 'GET') {
    return res.status(200).json({ message: 'ok' });
  }

  return res.status(405).send('');
};

export default healthCheckHandler;
// pages/index.js
// ...

export async function unstable_getStaticProps() {
  return {
    props: {
      healthcheck: (await fetch('localhost:3000/api/healthcheck').json())
    },
  };
}

由于服务器未运行,页面构建将在构建时崩溃。 我不确定这是否是一个有效的用例,因为getStaticProps不应该与任何过于动态的东西一起使用,但我认为这是一个有趣的边缘案例来分享(我完全可以想象一个负责获取的 Route API 端点来自另一个 API 的数据并重新格式化。

@martpie您可能想查看此评论: https :

下一代静态站点生成 (SSG) 支持已在 Next.js 9.3 中稳定发布!

此版本还包括对“预览模式”的支持,或者能够绕过静态预渲染页面并为授权用户按需渲染页面。

您可以在我们的博客文章中阅读更多相关信息。 如果您有更多的动手经验,请直接进入我们的文档

请将任何问题发布到Next.js GitHub 社区

这太酷了! 感谢您的辛勤工作!

这个新功能现在似乎不适用于 saga 和 redux

此页面是否有帮助?
0 / 5 - 0 等级