用storybook+webpack搭建react组件库
storybook 可以快速构建一个ui组件库的开发环境,本文将介绍完整的过程和一些踩的坑
- 初始化storybook项目
npx storybook init
初始化项目的时候可以选择创建webpack-react的项目
- 安装并启动项目
yarn
yarn storybook
如果启动有问题,需要手动安装一下react和react-dom
yarn add react react-dom --save
- 添加webpack配置,例如添加支持使用less文件的配置
- 安装包
yarn add css-loader less less-loader style-loader
- 修改.storybook下面的main.js
const path = require('path');
module.exports = {
"stories": [
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions"
],
"framework": "@storybook/react",
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /.less$/,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
importLoaders: 2,
modules: {
localIdentName: "[local]--[hash:base64:5]",
exportLocalsConvention: "camelCase",
},
},
},
{
loader: "less-loader",
},
],
include: path.resolve(__dirname, '../'),
});
return config;
}
}
到这里启动项目可能会报
this.getoptions is not a function,这是因为storybook默认使用的是webpack4,不支持高版本的style-loader或者less-loader
- 支持webpack5
yarn add @storybook/builder-webpack5 @storybook/manager-webpack5 --save-dev
再次修改.storybook下的main.js
const path = require('path');
module.exports = {
"stories": [
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions"
],
"framework": "@storybook/react",
core: {
builder: 'webpack5',
},
webpackFinal: async (config, { configType }) => {
// 同上,需要的webpack配置
}
}
- 在stories下编写自己的组件,脚手架搭的项目下也有一些例子
- 打包
- 安装webpack的相关包
yarn add webpack webpack-cli clean-webpacl-plugin --save
- 根目录下添加
webpack.config.js
const path = require('path');
const fs = require('fs');
const paths = require('./paths');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const useTypeScript = fs.existsSync(paths.appTsConfig);
module.exports = {
mode: 'production',
entry: {
index: './stories/index.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, "lib"),
publicPath: "/assets/",
libraryTarget: 'umd'
},
module: {
rules: [
{
test: /.(js|jsx|ts|tsx)$/,
include: [
path.resolve(__dirname, "stories")
],
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ['@babel/plugin-transform-runtime']
},
},
{
test: /.(less)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: {
// auto: /.module.\w+$/i,
localIdentName: "[local]--[hash:base64:5]",
exportLocalsConvention: "camelCase",
},
}
},
'less-loader'
],
}
],
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
},
resolve: {
extensions: paths.moduleFileExtensions
.map(ext => `.${ext}`)
.filter(ext => useTypeScript || !ext.includes('ts')),
},
plugins: [
new webpack.DefinePlugin(env.stringified),
new CleanWebpackPlugin(),
],
};
- 修改package.json
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"build": "webpack"
},