在vite项目中使用storybook
从 Storybook 6.3 开始,由于 Eirik Sletteberg、Sasan Farrokh 和 Ian VanSchooten 的英勇工作,您可以使用 Vite 来构建您的 Storybook。
当您将新构建器添加到您的项目时,Storybook 停止与 webpack 捆绑并开始与 Vite 捆绑。这意味着您可以获得以下好处:
- 显着提高了构建速度
- 与您的 Vite 项目设置的兼容性
- 访问 Vite 的插件生态系统
使用步骤说明
- 首先您需要创建一个vite项目(这里是vite react-ts)
npm init @vitejs/app vite-react-demo --template react-ts
cd vite-react-demo
npm i
- 初始化storybook
npx sb init --builder storybook-builder-vite
- 此时会自动多出两个文件夹
文件夹名称 | 作用 |
---|---|
.storybook | 配置文件 |
src/stories | 组件story案例 |
- 运行storybook
npm run storybook
- 运行成功截图
- story 案例代码说明(比如button)
// Button.ts
// import react from 'react'; // 如果使用17以及以上版本,不需要导入
import './button.css';
interface ButtonProps {
/**
* Is this the principal call to action on the page?
*/
primary?: boolean;
/**
* What background color to use
*/
backgroundColor?: string;
/**
* How large should the button be?
*/
size?: 'small' | 'medium' | 'large';
/**
* Button contents
*/
label: string;
/**
* Optional click handler
*/
onClick?: () => void;
}
/**
* Primary UI component for user interaction
*/
export const Button = ({
primary = false,
size = 'medium',
backgroundColor,
label,
...props
}: ButtonProps) => {
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
return (
<button
type="button"
className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
style={{ backgroundColor }}
{...props}
>
{label}
</button>
);
};
// Button.stories.ts
// import react from 'react'; // 如果使用17以及以上版本,不需要导入
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { Button } from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof Button>;
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Button',
};
// ...
对于Button.ts中ButtonProps interface申明,对应story的Doc是能自动推断出Description、Default、Control的,如下图所示 (TIPS: 下图是webpack项目截图):
而实际上vite项目,并没有自动推断出相关信息,说实话有点尴尬,目前还没找到解决方案(或许只能等官方发现,或者您知道可以下方留言)!!!
扩展配置!!!!!!!!
后期我在react-ts vite项目的基础上添加了以下配置
- postcss -> px to rem(我的项目是h5,所以要自适应手机端)
- vite.config.ts
使用到了vant,所以要作一些额外配置
// antd.theme.js
const theme = { // https://hub.fastgit.org/ant-design/ant-design-mobile/blob/master/components/style/themes/default.less
'@hd': '2px',
'@brand-primary': '#ff8a00',
'@brand-primary-tap': '#ee8a00',
'@brand-success': '#6abf47',
'@brand-warning': '#ffc600',
'@brand-error': '#f4333c',
'@brand-important': '#ff5b05', // 用于小红点
'@brand-wait': '#108ee9',
'color-text-base': '#333',
};
module.exports = theme;
// vite.config.ts
import path from 'path';
import reactRefresh from '@vitejs/plugin-react-refresh';
import styleImport from 'vite-plugin-style-import';
import { ConfigEnv, UserConfigExport } from 'vite';
const theme = require('./antd.theme');
// https://vitejs.dev/config/
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
const isBuild = command !== 'serve';
return {
clearScreen: false,
css: { // 使用到了vant自定义主题
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: theme,
},
},
},
server: {
port: 3003, // 端口自定义
},
resolve: {
alias: { // 文件目录缩写配置
'@': path.resolve('src'),
'@assets': path.resolve('src/assets'),
},
},
esbuild: { // 使用到了react17
jsxInject: `import React from 'react'`,
},
plugins: [
reactRefresh(),
styleImport({ // vant样式自动导入配置
libs: [
{
libraryName: 'antd-mobile',
esModule: true,
resolveComponent: (name) => {
return `antd-mobile/lib/${name}`;
},
resolveStyle: (name) => {
return `antd-mobile/es/${name}/style/index`;
},
},
],
}),
],
};
}
此时再次启动storybook,会报错,因为.storybook/main.js并没有这些配置,加上即可
const path = require('path');
const theme = require('../antd.theme');
// TIPS: 不支持import
const styleImport = require('vite-plugin-style-import').default;
module.exports = {
stories: [
'../src/**/*.stories.mdx',
'../src/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
],
core: {
builder: 'storybook-builder-vite',
},
async viteFinal(config, { configType: env }) {
// customize the Vite config here
const customConfig = {
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: theme,
},
},
},
resolve: {
alias: {
'@': path.resolve('src'),
'@assets': path.resolve('src/assets'),
},
},
esbuild: {
jsxInject: `import React from 'react'`,
},
};
config.plugins.push(
styleImport({
libs: [
{
libraryName: 'antd-mobile',
esModule: true,
resolveComponent: (name) => {
return `antd-mobile/lib/${name}`;
},
resolveStyle: (name) => {
return `antd-mobile/es/${name}/style/index`;
},
},
],
}),
);
// return the customized config
return { ...config, ...customConfig };
},
};
重新启动即可
接着看,还没完,由于我的项目自适应了手机端(postcss -> px to rem),所以按钮看上去非常小,原因是我们还需要在storybook中添加自适应基准字体大小设定
- 新建.storybook/preview-body.html
<script>
(function (doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
if (clientWidth >= 750) {
docEl.style.fontSize = '100px';
} else {
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
}
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
</script>
- 重启storybook,发现按钮大小正常显示
添加手机机型
- 编辑.storybook/preview.js
import { MINIMAL_VIEWPORTS } from '@storybook/addon-viewport';
const customViewports = {
pixel2: {
name: 'Pixel 2',
styles: {
width: '411px',
height: '731px',
},
},
iphone5: {
name: 'iPhone 5/SE',
styles: {
width: '320px',
height: '568px',
},
},
iphone678: {
name: 'iPhone 6/7/8',
styles: {
width: '375px',
height: '667px',
},
},
};
// https://storybook.js.org/docs/react/essentials/viewport
export const parameters = {
padded: false,
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
viewport: {
viewports: {
...MINIMAL_VIEWPORTS,
...customViewports,
},
},
};
- 重启storybook,并点击红框中的按钮
- 选择任意一个自定义机型,比如iPhone5/SE
设置成功!
编辑于 2021-07-06 17:45