Next.js是一个在React中构建高性能应用程序的神奇框架。但随着它变得越来越先进--拥有next/image这样的功能--它变得越来越难以与Storybook这样的文档和测试环境整合。
我深入研究了如何使Storybook成为Next.js页面的最佳组件驱动的UI环境。这篇文章向你展示了如何通过四个简单的步骤完成同样的工作:
- 📦 用Webpack 5初始化一个新的Storybook
- 📑 为Next.js页面创建故事
- 🌎 在preview.js中导入共享、全局样式
- ⬇️为故事中使用的Next Image进行去优化
如果你喜欢视频,请跳到最后。我们在一个27分钟的YouTube视频中涵盖了所有这些步骤(以及更多)。
从Next.js应用程序开始
在我们开始之前,我们需要一个Next.js应用程序。本教程使用nextjs.org上的精彩入门指南:

在浏览器中运行的全新Next.js应用程序
我建议在一个新的应用程序中进行学习,然后在一个现有的应用程序中重复这些步骤。以下是Github上的完整源代码,已针对Next.js 12进行了更新。
用Webpack 5初始化一个新的Storybook
Storybook有一个初始化器,为我们做了大量工作:npx sb init 。这个脚本会检测你的项目类型并适应它。但我们也可以给它一些提示。
Next.js v11及以后的版本使用Webpack 5。我们也可以在Storybook中使用Webpack 5来获得更好的集成度和性能。要做到这一点,我们使用builder 选项并运行这个命令:
npx sb init --builder webpack5
为完整的Next.js页面创建故事
Next.js和Storybook有极其兼容的组件模型。Next.js将组件用于页面,Storybook将组件用于文档和测试。这使得Storybook成为Next.js的一个伟大的组件驱动的开发环境!
让我们为我们的Next.js主页创建一个故事:
- 创建一个新文件
/stories/pages/home.stories.jsx - 导入
/pages/index.js - 导出一个默认的故事对象,带有
title和component属性 - 导出一个故事给
Home
// /stories/pages/home.stories.jsx
import Home from "../../pages/index";
export default {
title: "Pages/Home",
component: Home,
};
export const HomePage = () => <Home />
现在我们在Storybook中拥有了我们的主页。但它还没有什么可看的。我们需要导入全局样式:

在preview.js中导入共享的全局样式表
大多数应用程序都有全局重置或字体样式的样式表,这些样式表是全局共享的。我们的Next.js教程应用将全局样式保存在/styles/globals.css 。
我们可以将全局样式表导入我们的home.stories.jsx 故事文件中。但这样做需要在故事文件中进行大量的重复,这是一个非常容易出错的过程。最好的办法是为所有的故事导入一个全局样式表。
故事书在.storybook/preview.js 中持有共享的故事配置。这个文件控制着所有故事的渲染方式。样式表可以用模块导入的方式导入:
// .storybook/preview.js
import "../styles/globals.css";


Story,在添加 globals.css 之前和之后。好多了!
我们成功了!除了一张破损的图片之外,我们的故事看起来就像Next.js提供的主页。
关于在Storybook中处理样式的更多方法,请查看我们的样式和CSS指南。
对故事中的Next.js图像进行去优化
Next.js和Storybook集成中最具挑战性的部分是处理图像:

必须将Storybook配置为在/public目录下提供Next/images服务。
Next.js v10和更新版本包括Next.js图像组件。用他们的话说,它是*"HTML<img>元素的扩展,为现代网络而演变"。*利用它可以优化文件大小、视觉稳定性和加载时间。它是UI工程的一个奇迹。
因为Storybook是在与Next.js框架集成隔离的情况下运行这些组件的,所以我们需要在两个重要方面对其进行配置:
- 在Storybook中为Next.js
public目录提供服务 - 在所有故事中为Next.js图像组件添加
unoptimized道具
1.在Storybook中服务于公共目录
sb init 脚本在我们的package.json 中创建了两个Storybook脚本。更新这两个脚本以服务于public目录(Next.js图像保存在这里)。我们为此使用的CLI选项是-s 。或--static-dir :
// package.json
"scripts": {
- "storybook": "start-storybook -p 6006",
- "build-storybook": "build-storybook"
+ "storybook": "start-storybook -p 6006 -s ./public",
+ "build-storybook": "build-storybook -s public"
}
在我们的CLI选项文档中找到更多CLI选项。并了解更多关于通过Storybook服务静态文件的信息。
2.在Storybook中为Next.js图像使用未优化的道具
在使用Next.js图像组件的任何地方,图像都是从/_next-预设的路径提供的。我们想利用Next Image的道具API和属性,但我们不希望要求Next.js开发服务器正在运行。我们完全可以用unoptimized 道具来做到这一点。但我们如何在Storybook中做到这一点,而不是在Next.js中🤔?
通过一些模块的技巧,我们可以只在故事中取消对Next.js Image的优化:
// .storybook/preview.js
import * as NextImage from "next/image";
const OriginalNextImage = NextImage.default;
Object.defineProperty(NextImage, "default", {
configurable: true,
value: (props) => <OriginalNextImage {...props} unoptimized />,
});
这段配置修改了Storybook对next/image 模块的评估方式。凡是使用Next.js Image的默认输出的地方,都会应用unoptimized 这个道具。
重新启动你的服务器,看看底部的Vercel SVG。我们又开始工作了!
有关这一技术的更多信息,请阅读如何在Storybook中使用Next.js图像组件--Jonas Schumacher的一篇精彩文章:


Next.js主页作为应用程序运行(左),并在Storybook中独立运行(右)。