在 Next.js/Webpack 5 中安装 Plaiceholder 会导致:找不到模块:无法解析 'child_process'

Installing Plaiceholder in Next.js / Webpack 5 causes: Module not found: Can't resolve 'child_process'

我正在构建 Next.js 应用程序,当我安装/导入 Plaiceholder(用于生成占位符图像)时,出现以下错误:Module not found: Can't resolve 'child_process'

我理解此错误消息的意思是 webpack5 正在尝试捆绑客户端无法使用的节点包。但我不清楚为什么要这样做。我没有自定义任何 webpack 配置,我在 Plaiceholder 文档中找不到任何关于这个问题的提及。我该如何解决?

注意:我希望在构建期间创建 base64 数据 URL,以便在页面加载后立即可用(而不是在 运行 时异步获取)。

这是我的 next.config.js

module.exports = {
  reactStrictMode: true,
};

我的package.json只有scriptsdependenciesdevDependencies(没有改变模块分辨率)

如果相关,这里有一个使用 Plaiceholder 的简化示例:

import Image from "next/image";
import { getPlaiceholder } from "plaiceholder";
import React, { useState } from "react";

...

const { base64 } = await getPlaiceholder(imgUrl);

...

return (<Image
            src={imgUrl}
            placeholder="blur"
            blurDataURL={base64}
          />);

plaiceholder好像不适合做客户端渲染。我相信该软件包适用于 Node.js 环境。这就是当您尝试在客户端呈现组件时出现此错误的原因。

要解决这个问题,需要将import { getPlaiceholder } from 'plaiceholder'移动到NextJS API部分。然后,您可以使用正文中的 URL 数据来调用 API。然后获取base64.

/api/getBase64.js

import { getPlaiceholder } from "plaiceholder";

export default async (req, res) => {
  const { body } = req;
  const { url } = body;

  const { base64 } = getPlaiceholder(url);

  res.status(200).send(base64);
};

/component.js

import Image from "next/image";
import React, { useState, useEffect } from "react";

const [base64, setBase64] = useState()

useEffect(() => {
  (async () => {
   const _base64 = await fetch.post('/api/getBase64', {url: imgUrl}); // wrote for demonstration
   setBase64(_base64);
  })()
})

return (<Image
            src={imgUrl}
            placeholder="blur"
            blurDataURL={base64}
          />);

我知道 blurDataURL 在您获取数据之前将是未定义的,但这是您可以使用 plaiceholder 库管理图像的方式。它应该仅为 NodeJS 环境导入。如果你不喜欢这种方式,你可以尝试寻找另一个同样适用于浏览器环境(客户端)的库

根据评论更新:

如果要在构建时生成此 base64,可以在使用此 Image 组件的页面中使用 getStaticProps。 NextJS 足够聪明,可以理解在客户端或服务器端使用了哪些库。所以你可以这样做:

import { getPlaiceholder } from "plaiceholder";  // place it at the root of file. This will not be bundled inside of client-side code

export async function getStaticProps(context) {
  const { base64 } = await getPlaiceholder(imgUrl);

  return {
    props: { base64 }, // will be passed to the page component as props
  }
}

这样,通过使用 getStaticProps,页面将在构建时创建。您可以在使用图像组件的页面内获取 base64 属性并将该属性传递给 blurDataURL。此外,您也可以将此方法与 getServerSideProps 一起使用。

这是来自 NextJS 网站:

Note: You can import modules in top-level scope for use in getServerSideProps. Imports used in getServerSideProps will not be bundled for the client-side.

https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering